Skip to content

Display RBS type signatures in documentation#1665

Draft
st0012 wants to merge 2 commits intomasterfrom
integrate-rbs
Draft

Display RBS type signatures in documentation#1665
st0012 wants to merge 2 commits intomasterfrom
integrate-rbs

Conversation

@st0012
Copy link
Copy Markdown
Member

@st0012 st0012 commented Mar 30, 2026

Summary

Extract #: inline RBS annotations from comments and display them alongside method/attribute documentation in RDoc's HTML output.

  • Parse #: annotation lines from comment blocks during Prism parsing, store as type_signature on MethodAttr
  • Load type signatures from sig/ directory and RBS core types via RBS::EnvironmentLoader (inline annotations take priority)
  • Validate annotations through RBS::Parser with warnings for invalid syntax
  • Server-side type name linking using RBS parser locations — type names link to their documentation pages
  • Render type signatures in the aliki theme with a dotted separator between call_seq and type sigs
  • Display type signatures in ri terminal output
  • Add rbs >= 4.0.0 as a gemspec dependency, bump minimum Ruby to 3.2

Builds on #1669 (signature card design).

Screenshots

Screenshot 2026-04-02 at 18 31 13

Implementation

Area Details
Data model type_signature accessor on MethodAttr, Marshal v4
Parser extract_type_signature! in PrismRuby, validates via both parse_method_type and parse_type
sig/ loading RDoc::RbsSupport.load_signatures via RBS::EnvironmentLoader, merged after store.complete
Type linking Server-side via RbsSupport.signature_to_html using RBS parser AST locations, decoupled from generator via block
Display Aliki theme — template, CSS; tertiary color, tight line-height, dotted separator, scaled on mobile
RI output render_method_type_signature in ri/driver.rb
Caching Store#type_name_lookup built once, invalidated on complete
Tests Parser, marshal, RBS support, type linking, ri output

Follow-up work

  • Merge RBS sigs with method params: Type signatures could be merged with call_seq parameters (e.g., showing typed params with default values). Deferred — significantly more complex.
  • JRuby/TruffleRuby support: RBS has a C extension that cannot build on these platforms. Dropped from CI for now. Future work: make rbs an optional dependency with graceful degradation.

@matzbot
Copy link
Copy Markdown
Collaborator

matzbot commented Mar 30, 2026

🚀 Preview deployment available at: https://a8f19ac8.rdoc-6cd.pages.dev (commit: 25103b6)

@st0012 st0012 changed the base branch from master to signature-card-design April 2, 2026 17:29
@st0012 st0012 force-pushed the signature-card-design branch from 251f5db to be86678 Compare April 2, 2026 18:05
@st0012 st0012 force-pushed the integrate-rbs branch 4 times, most recently from a469122 to bfcd437 Compare April 2, 2026 22:17
@st0012 st0012 force-pushed the signature-card-design branch from be86678 to 4b26c40 Compare April 9, 2026 14:54
Base automatically changed from signature-card-design to master April 9, 2026 15:04
st0012 added 2 commits April 9, 2026 18:52
RBS 4.0 requires Ruby >= 3.2. Bump RDoc's own minimum to match and
add `rbs >= 4.0.0` as a gemspec dependency. Bump prism minimum to
`>= 1.6.0` (required by rbs). Drop JRuby and TruffleRuby from CI
matrix (rbs has a C extension that cannot build on them).
Add `type_signature` accessor to `MethodAttr`. During Prism parsing,
extract `#:` annotation lines from comment blocks and store them on
methods and attributes. Bump Marshal to v4 for RI serialization.

Render type signatures in the aliki theme with server-side type name
linking via `RbsSupport.signature_to_html`. Uses the RBS parser to
extract type name locations precisely for linking to documentation
pages. Validate annotations through `RBS::Parser` — invalid sigs
emit a warning but are still displayed.

Load additional signatures from `sig/` directories and RBS core
types via `RBS::EnvironmentLoader`. Display type signatures in `ri`
terminal output.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds first-class support for RBS type signatures in RDoc by extracting inline #: annotations during parsing, optionally loading signatures from .rbs files, and rendering those signatures in both HTML (Aliki theme) and ri terminal output.

Changes:

  • Extract #: type signatures from comment blocks in the Prism parser and attach them to RDoc::MethodAttr objects.
  • Load/merge signatures from RBS sources into the store (without overwriting inline annotations) and add type-name linking in HTML output.
  • Render signatures in Aliki HTML + ri, update marshal formats, and bump runtime requirements (Ruby >= 3.2, add rbs dependency).

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
lib/rdoc/parser/prism_ruby.rb Extracts/validates inline #: signatures and attaches them to methods/attrs.
lib/rdoc/rbs_support.rb New RBS integration: validation, signature loading, and HTML linking.
lib/rdoc/store.rb Adds signature merge logic and cached type-name lookup for linking.
lib/rdoc/generator/aliki.rb Exposes type_signature_html helper for templates (linked type names).
lib/rdoc/generator/template/aliki/class.rhtml Renders type signatures for methods and attributes in HTML output.
lib/rdoc/generator/template/aliki/css/rdoc.css Styles signature blocks and linked type names.
lib/rdoc/generator/template/aliki/js/aliki.js Avoids wrapping signature <pre> blocks with “copy” UI.
lib/rdoc/ri/driver.rb Prints method type signatures in ri output.
lib/rdoc/code_object/method_attr.rb Adds type_signature storage + line splitting helper.
lib/rdoc/code_object/any_method.rb Bumps marshal version and persists type_signature.
lib/rdoc/code_object/attr.rb Bumps marshal version and persists type_signature.
lib/rdoc/rdoc.rb Loads RBS signatures after store completion and merges into objects.
rdoc.gemspec Bumps Ruby minimum to 3.2, adds rbs dependency, bumps prism minimum.
Gemfile Always includes mini_racer on MRI (Ruby >= 3.2 now required).
.github/workflows/test.yml Aligns CI with Ruby >= 3.2 and updated Prism versions.
test/rdoc/parser/prism_ruby_test.rb Adds Prism-only tests for inline signature extraction.
test/rdoc/rbs_support_test.rb New tests for validation, loading, and HTML linking.
test/rdoc/rdoc_store_test.rb Tests signature merging + type_name_lookup behavior/caching.
test/rdoc/ri/driver_test.rb Tests ri output includes a type signature.
test/rdoc/code_object/any_method_test.rb Tests marshal persistence for method type signatures.
test/rdoc/code_object/attr_test.rb Tests marshal persistence for attribute type signatures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +852 to +861
def extract_type_signature!(text)
return nil unless text.include?('#:')

lines = text.lines
sig_lines, doc_lines = lines.partition { |l| l.match?(/\A#:\s/) }
return nil if sig_lines.empty?

text.replace(doc_lines.join)
type_sig = sig_lines.map { |l| l.sub(/\A#:\s?/, '').chomp }.join("\n")
validate_type_signature(type_sig)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract_type_signature! only recognizes signature lines that match /\A#:\s/, so an annotation like #:String (no whitespace) will not be extracted even though the later sub(/\A#:\s?/, ...) implies it should be supported. Consider loosening the match to accept #: with optional whitespace so the extraction and stripping logic are consistent.

Copilot uses AI. Check for mistakes.
next unless method_error
type_error = RDoc::RbsSupport.validate_type(line)
next unless type_error
@options.warn "Invalid RBS type signature: #{line.inspect}"
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invalid-signature warning drops the actual parse error details even though validate_method_type / validate_type return an error message. Including the parser error (or at least whether it failed as a method type vs. a plain type) would make the warning actionable when users mistype an annotation.

Suggested change
@options.warn "Invalid RBS type signature: #{line.inspect}"
@options.warn "Invalid RBS type signature: #{line.inspect} " \
"(method type parse failed: #{method_error}; " \
"type parse failed: #{type_error})"

Copilot uses AI. Check for mistakes.
Comment on lines +865 to +872
def validate_type_signature(sig)
sig.split("\n").each do |line|
method_error = RDoc::RbsSupport.validate_method_type(line)
next unless method_error
type_error = RDoc::RbsSupport.validate_type(line)
next unless type_error
@options.warn "Invalid RBS type signature: #{line.inspect}"
end
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file references RDoc::RbsSupport, but RDoc::RbsSupport is not autoloaded in lib/rdoc.rb (it’s not in the autoload list) and lib/rdoc/parser/prism_ruby.rb doesn’t require it. If the Prism parser is used without first loading rdoc/rdoc, this will raise NameError. Consider adding an explicit require 'rdoc/rbs_support' (or adding an autoload entry) to guarantee the constant is available.

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +47
def load_signatures(*dirs)
loader = RBS::EnvironmentLoader.new
dirs.each { |dir| loader.add(path: Pathname(dir)) }

env = RBS::Environment.new
loader.load(env: env)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load_signatures uses Pathname(dir) but the file doesn’t require 'pathname'. Relying on transitive requires (e.g., via rbs) is fragile and can cause NameError: uninitialized constant Pathname when RDoc::RbsSupport is required directly. Add an explicit require 'pathname' (or avoid Pathname).

Copilot uses AI. Check for mistakes.
Comment on lines +354 to +357
all_classes_and_modules.each do |cm|
lookup[cm.full_name] = cm.path
lookup[cm.name] = cm.path unless lookup.key?(cm.name)
end
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type_name_lookup maps short names (e.g., SubClass) to the first class/module encountered, which can produce incorrect/unstable links when multiple constants share the same short name. To avoid wrong cross-links, consider only adding short-name entries when the short name is unique (or track ambiguity and skip linking for ambiguous short names).

Suggested change
all_classes_and_modules.each do |cm|
lookup[cm.full_name] = cm.path
lookup[cm.name] = cm.path unless lookup.key?(cm.name)
end
short_name_lookup = {}
ambiguous_short_names = {}
all_classes_and_modules.each do |cm|
lookup[cm.full_name] = cm.path
next if ambiguous_short_names[cm.name]
if short_name_lookup.key?(cm.name)
short_name_lookup.delete cm.name
ambiguous_short_names[cm.name] = true
else
short_name_lookup[cm.name] = cm.path
end
end
lookup.merge! short_name_lookup

Copilot uses AI. Check for mistakes.
attr_accessor :call_seq

##
# RBS type signature from inline #: annotations
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says type_signature is “from inline #: annotations”, but merge_rbs_signatures also populates type_signature from loaded .rbs files. Updating this comment to reflect both sources would keep the documentation accurate.

Suggested change
# RBS type signature from inline #: annotations
# RBS type signature from inline #: annotations or loaded .rbs files

Copilot uses AI. Check for mistakes.
Comment on lines +124 to +133
def type_signature_html(method_attr, from_path)
lines = method_attr.type_signature_lines
return unless lines

RDoc::RbsSupport.signature_to_html(
lines,
lookup: @store.type_name_lookup,
from_path: from_path
)
end
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generator calls RDoc::RbsSupport.signature_to_html, but RDoc::RbsSupport is not autoloaded in lib/rdoc.rb and lib/rdoc/generator/aliki.rb doesn’t require it. If the generator is used without loading rdoc/rdoc first, this can raise NameError. Consider requiring rdoc/rbs_support (or adding an autoload entry) to make the dependency explicit.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants