Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
ruby-versions:
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
with:
# 2.7 breaks `test_parse_statements_nodoc_identifier_alias_method`
min_version: 3.0
min_version: 3.2
versions: '["mswin"]'
engine: cruby

test:
needs: ruby-versions
Expand All @@ -26,14 +26,6 @@ jobs:
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
os: [ubuntu-latest, macos-latest, windows-latest]
exclude:
- os: windows-latest
ruby: truffleruby
- os: windows-latest
ruby: truffleruby-head
- os: windows-latest
ruby: jruby
- os: windows-latest
ruby: jruby-head
- os: macos-latest
ruby: mswin
- os: ubuntu-latest
Expand Down Expand Up @@ -68,7 +60,7 @@ jobs:
strategy:
fail-fast: false
matrix:
prism_version: ['1.0.0', '1.3.0', '1.7.0', 'head']
prism_version: ['1.6.0', '1.7.0', 'head']
runs-on: ubuntu-latest
env:
RUBYOPT: --enable-frozen_string_literal
Expand Down
4 changes: 1 addition & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,5 @@ elsif ENV['PRISM_VERSION']
end

platforms :ruby do
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.2')
gem 'mini_racer' # For testing the searcher.js file
end
gem 'mini_racer' # For testing the searcher.js file
end
4 changes: 3 additions & 1 deletion lib/rdoc/code_object/any_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class RDoc::AnyMethod < RDoc::MethodAttr
# RDoc 4.1
# Added is_alias_for

MARSHAL_VERSION = 3 # :nodoc:
MARSHAL_VERSION = 4 # :nodoc:

##
# Don't rename \#initialize to \::new
Expand Down Expand Up @@ -166,6 +166,7 @@ def marshal_dump
@parent.class,
@section.title,
is_alias_for,
@type_signature,
]
end

Expand Down Expand Up @@ -204,6 +205,7 @@ def marshal_load(array)
@parent_title = array[13]
@section_title = array[14]
@is_alias_for = array[15]
@type_signature = array[16]

array[8].each do |new_name, document|
add_alias RDoc::Alias.new(nil, @name, new_name, RDoc::Comment.from_document(document), singleton: @singleton)
Expand Down
6 changes: 4 additions & 2 deletions lib/rdoc/code_object/attr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class RDoc::Attr < RDoc::MethodAttr
# Added parent name and class
# Added section title

MARSHAL_VERSION = 3 # :nodoc:
MARSHAL_VERSION = 4 # :nodoc:

##
# Is the attribute readable ('R'), writable ('W') or both ('RW')?
Expand Down Expand Up @@ -108,7 +108,8 @@ def marshal_dump
@file.relative_name,
@parent.full_name,
@parent.class,
@section.title
@section.title,
@type_signature,
]
end

Expand Down Expand Up @@ -140,6 +141,7 @@ def marshal_load(array)
@parent_name = array[8]
@parent_class = array[9]
@section_title = array[10]
@type_signature = array[11]

@file = RDoc::TopLevel.new array[7] if version > 1

Expand Down
6 changes: 6 additions & 0 deletions lib/rdoc/code_object/method_attr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class RDoc::MethodAttr < RDoc::CodeObject

attr_accessor :call_seq

##
# RBS type signature from inline #: annotations

attr_accessor :type_signature

##
# The call_seq or the param_seq with method name, if there is no call_seq.

Expand Down Expand Up @@ -86,6 +91,7 @@ def initialize(text, name, singleton: false)
@block_params = nil
@call_seq = nil
@params = nil
@type_signature = nil
end

##
Expand Down
20 changes: 20 additions & 0 deletions lib/rdoc/generator/markup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ def markup_code
src
end

##
# Returns the type signature as HTML with type names linked to their
# documentation pages. Delegates to RDoc::RbsSupport for RBS-aware parsing.
#
# Falls back to escaped HTML without links when the store or parent
# path is unavailable (e.g. in ri mode).

def type_signature_html
return unless @type_signature

store = @store || parent&.store
from_path = parent&.path
lookup = store&.type_name_lookup

RDoc::RbsSupport.signature_to_html(@type_signature, lookup: lookup) do |name, target_path|
href = RDoc::Markup::ToHtml.gen_relative_url(from_path, target_path)
"<a href=\"#{href}\" class=\"rbs-type\">#{ERB::Util.html_escape(name)}</a>"
end
end

end

class RDoc::ClassModule
Expand Down
9 changes: 7 additions & 2 deletions lib/rdoc/generator/template/aliki/class.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@
<div class="method-heading attribute-method-heading">
<a href="#<%= attrib.aref %>" title="Link to this attribute">
<span class="method-name"><%= h attrib.name %></span>
<span class="attribute-access-type">[<%= attrib.rw %>]</span>
</a>
<span class="attribute-access-type">[<%= attrib.rw %>]</span></a><%- if attrib.type_signature %>
<span class="method-type-signature"><code><%= attrib.type_signature_html %></code></span>
<%- end %>
</div>

<div class="method-description">
Expand Down Expand Up @@ -150,6 +151,10 @@
</a>
</div>
<%- end %>

<%- if method.type_signature %>
<pre class="method-type-signature"><code><%= method.type_signature_html %></code></pre>
<%- end %>
</div>

<%- if method.token_stream %>
Expand Down
61 changes: 61 additions & 0 deletions lib/rdoc/generator/template/aliki/css/rdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,20 @@ main h6 a:hover {
font-style: italic;
}

/* RBS Type Signature Links — linked types get subtle underline */
a.rbs-type {
color: inherit;
text-decoration: underline;
text-decoration-color: var(--color-border-default);
text-underline-offset: 0.2em;
transition: text-decoration-color var(--transition-fast), color var(--transition-fast);
}

a.rbs-type:hover {
color: var(--color-link-hover);
text-decoration-color: var(--color-link-hover);
}

/* Emphasis */
em {
text-decoration-color: var(--color-emphasis-decoration);
Expand Down Expand Up @@ -1334,6 +1348,49 @@ main .method-heading .method-args {
font-weight: var(--font-weight-normal);
}

/* Type signatures — overloads stack as a code block under the method name */
pre.method-type-signature {
position: relative;
margin: var(--space-2) 0 0;
padding: var(--space-2) 0 0;
background: transparent;
border: none;
border-radius: 0;
overflow: visible;
font-family: var(--font-code);
font-size: var(--font-size-sm);
color: var(--color-text-tertiary);
line-height: var(--line-height-tight);
white-space: pre-wrap;
overflow-wrap: break-word;
}

pre.method-type-signature::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
border-top: 1px dotted var(--color-border-default);
}

pre.method-type-signature code {
font-family: inherit;
font-size: inherit;
color: inherit;
background: transparent;
padding: 0;
}

/* Attribute type sigs render inline after the [RW] badge */
main .method-heading > .method-type-signature {
display: inline;
margin-left: var(--space-2);
font-family: var(--font-code);
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
}

main .method-controls {
position: absolute;
top: var(--space-3);
Expand Down Expand Up @@ -1440,6 +1497,10 @@ main .attribute-access-type {
font-size: var(--font-size-base);
}

pre.method-type-signature {
font-size: var(--font-size-xs);
}

main .method-header {
padding: var(--space-2);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/rdoc/generator/template/aliki/js/aliki.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@ function wrapCodeBlocksWithCopyButton() {
// not directly in rhtml templates
// - Modifying the formatter would require extending RDoc's core internals

// Find all pre elements that are not already wrapped
const preElements = document.querySelectorAll('main pre:not(.code-block-wrapper pre)');
// Target code examples and source code; skip type signature blocks
const preElements = document.querySelectorAll('main pre:not(.method-type-signature)');

preElements.forEach((pre) => {
// Skip if already wrapped
Expand Down
43 changes: 38 additions & 5 deletions lib/rdoc/parser/prism_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,37 @@ def skip_comments_until(line_no_until)
def consecutive_comment(line_no)
return unless @unprocessed_comments.first&.first == line_no
_line_no, start_line, text = @unprocessed_comments.shift
parse_comment_text_to_directives(text, start_line)
type_signature = extract_type_signature!(text)
result = parse_comment_text_to_directives(text, start_line)
return unless result
comment, directives = result
[comment, directives, type_signature]
end

# Extracts RBS type signature lines (#: ...) from raw comment text.
# Mutates the input text to remove the extracted lines.
# Returns the type signature string, or nil if none found.
private 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)
type_sig
end

private 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
end

# Parses comment text and retuns a pair of RDoc::Comment and directives
Expand Down Expand Up @@ -594,14 +624,15 @@ def add_alias_method(old_name, new_name, line_no)
# Handles `attr :a, :b`, `attr_reader :a, :b`, `attr_writer :a, :b` and `attr_accessor :a, :b`

def add_attributes(names, rw, line_no)
comment, directives = consecutive_comment(line_no)
comment, directives, type_signature = consecutive_comment(line_no)
handle_code_object_directives(@container, directives) if directives
return unless @container.document_children

names.each do |symbol|
a = RDoc::Attr.new(nil, symbol.to_s, rw, comment, singleton: @singleton)
a.store = @store
a.line = line_no
a.type_signature = type_signature
record_location(a)
handle_modifier_directive(a, line_no)
@container.add_attribute(a) if should_document?(a)
Expand Down Expand Up @@ -640,7 +671,7 @@ def add_extends(names, line_no) # :nodoc:

def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:, start_line:, args_end_line:, end_line:)
receiver = receiver_name ? find_or_create_module_path(receiver_name, receiver_fallback_type) : @container
comment, directives = consecutive_comment(start_line)
comment, directives, type_signature = consecutive_comment(start_line)
handle_code_object_directives(@container, directives) if directives

internal_add_method(
Expand All @@ -655,11 +686,12 @@ def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:
params: params,
calls_super: calls_super,
block_params: block_params,
tokens: tokens
tokens: tokens,
type_signature: type_signature
)
end

private def internal_add_method(method_name, container, comment:, dont_rename_initialize: false, directives:, modifier_comment_lines: nil, line_no:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:) # :nodoc:
private def internal_add_method(method_name, container, comment:, dont_rename_initialize: false, directives:, modifier_comment_lines: nil, line_no:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:, type_signature: nil) # :nodoc:
meth = RDoc::AnyMethod.new(nil, method_name, singleton: singleton)
meth.comment = comment
handle_code_object_directives(meth, directives) if directives
Expand All @@ -680,6 +712,7 @@ def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:
meth.params ||= params || '()'
meth.calls_super = calls_super
meth.block_params ||= block_params if block_params
meth.type_signature = type_signature
record_location(meth)
meth.start_collecting_tokens(:ruby)
tokens.each do |token|
Expand Down
Loading