Skip to content
Open
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
13 changes: 13 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,18 @@ class RDoc::MethodAttr < RDoc::CodeObject

attr_accessor :call_seq

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

attr_accessor :type_signature

##
# Returns the type signature split into individual lines.

def type_signature_lines
@type_signature&.split("\n")
end
Comment on lines +69 to +71

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

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

##
Expand Down
15 changes: 15 additions & 0 deletions lib/rdoc/generator/aliki.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ def write_search_index
File.write search_index_path, "var search_data = #{JSON.generate(data)};"
end

##
# Returns the type signature of +method_attr+ as HTML with linked type names.
# Returns nil if no type signature is present.

def type_signature_html(method_attr, from_path)
lines = method_attr.type_signature_lines
return unless lines

RDoc::RbsHelper.signature_to_html(
lines,
lookup: @store.type_name_lookup,
from_path: from_path
)
end

##
# Resolves a URL for use in templates. Absolute URLs are returned unchanged.
# Relative URLs are prefixed with rel_prefix to ensure they resolve correctly from any page.
Expand Down
7 changes: 7 additions & 0 deletions lib/rdoc/generator/template/aliki/class.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
<span class="method-name"><%= h attrib.name %></span>
<span class="attribute-access-type">[<%= attrib.rw %>]</span>
</a>
<%- if attrib.type_signature %>
<span class="method-type-signature"><code><%= type_signature_html(attrib, klass.path) %></code></span>
<%- end %>
</div>

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

<%- if method.type_signature %>
<pre class="method-type-signature"><code><%= type_signature_html(method, klass.path) %></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 @@ -1335,6 +1349,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 @@ -1444,6 +1501,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);
padding-right: 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
68 changes: 62 additions & 6 deletions lib/rdoc/parser/prism_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ class RDoc::Parser::PrismRuby < RDoc::Parser

parse_files_matching(/\.rbw?$/) unless ENV['RDOC_USE_RIPPER_PARSER']

# Matches an RBS inline type annotation line: #: followed by whitespace
RBS_SIG_LINE = /\A#:\s/ # :nodoc:

attr_accessor :visibility
attr_reader :container, :singleton, :in_proc_block

Expand Down Expand Up @@ -461,10 +464,14 @@ 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, start_line)
result = parse_comment_text_to_directives(text, start_line)
return unless result
comment, directives = result
[comment, directives, type_signature]
end

# Parses comment text and retuns a pair of RDoc::Comment and directives
# Parses comment text and returns a pair of RDoc::Comment and directives

def parse_comment_text_to_directives(comment_text, start_line) # :nodoc:
comment_text, directives = @preprocess.parse_comment(comment_text, start_line, :ruby)
Expand Down Expand Up @@ -594,14 +601,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 +648,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 +663,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 +689,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 Expand Up @@ -836,6 +846,52 @@ def add_module_or_class(module_name, start_line, end_line, is_class: false, supe
mod
end

private

# 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.

def extract_type_signature!(text, start_line)
return nil unless text.include?('#:')

sig_lines, doc_lines, first_sig_line = split_sig_lines(text.lines, start_line)
return nil if sig_lines.empty?

text.replace(doc_lines.join)
type_sig = sig_lines.map { |l| l.sub(RBS_SIG_LINE, '') }.join.chomp
return nil if type_sig.strip.empty?

warn_invalid_type_signature(type_sig, first_sig_line)
type_sig
end
Comment on lines +855 to +867

# Splits comment lines into signature lines and doc lines,
# returning [sig_lines, doc_lines, first_sig_line_number].

def split_sig_lines(lines, start_line) # :nodoc:
sig_lines = []
doc_lines = []
first_sig_line = nil
lines.each_with_index do |line, i|
if line.match?(RBS_SIG_LINE)
first_sig_line ||= start_line + i
sig_lines << line
else
doc_lines << line
end
end
[sig_lines, doc_lines, first_sig_line]
end

def warn_invalid_type_signature(sig, line_no)
sig.each_line(chomp: true).with_index do |line, i|
next if RDoc::RbsHelper.valid_method_type?(line)
next if RDoc::RbsHelper.valid_type?(line)
@options.warn "#{@top_level.relative_name}:#{line_no + i}: invalid RBS type signature: #{line.inspect}"
end
end

class RDocVisitor < Prism::Visitor # :nodoc:
def initialize(scanner, top_level, store)
@scanner = scanner
Expand Down
Loading