yard 0.9.38 → 0.9.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -1
- data/README.md +18 -21
- data/docs/GettingStarted.md +41 -15
- data/docs/Tags.md +5 -5
- data/docs/WhatsNew.md +59 -7
- data/docs/templates/default/yard_tags/html/setup.rb +1 -1
- data/lib/yard/autoload.rb +17 -0
- data/lib/yard/cli/diff.rb +7 -2
- data/lib/yard/code_objects/proxy.rb +1 -1
- data/lib/yard/handlers/processor.rb +1 -0
- data/lib/yard/handlers/rbs/attribute_handler.rb +43 -0
- data/lib/yard/handlers/rbs/base.rb +38 -0
- data/lib/yard/handlers/rbs/constant_handler.rb +18 -0
- data/lib/yard/handlers/rbs/method_handler.rb +327 -0
- data/lib/yard/handlers/rbs/mixin_handler.rb +20 -0
- data/lib/yard/handlers/rbs/namespace_handler.rb +26 -0
- data/lib/yard/handlers/ruby/attribute_handler.rb +7 -4
- data/lib/yard/handlers/ruby/constant_handler.rb +1 -0
- data/lib/yard/i18n/locale.rb +1 -1
- data/lib/yard/i18n/pot_generator.rb +1 -1
- data/lib/yard/parser/rbs/rbs_parser.rb +325 -0
- data/lib/yard/parser/rbs/statement.rb +75 -0
- data/lib/yard/parser/ruby/legacy/irb/slex.rb +19 -1
- data/lib/yard/parser/ruby/ruby_parser.rb +55 -3
- data/lib/yard/parser/source_parser.rb +3 -2
- data/lib/yard/registry_resolver.rb +7 -0
- data/lib/yard/rubygems/specification.rb +1 -1
- data/lib/yard/server/library_version.rb +1 -1
- data/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js +208 -12
- data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +1 -17
- data/lib/yard/server/templates/default/method_details/html/permalink.erb +4 -2
- data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +3 -3
- data/lib/yard/server/templates/doc_server/library_list/html/library_list.erb +2 -3
- data/lib/yard/server/templates/doc_server/processing/html/processing.erb +22 -16
- data/lib/yard/tags/directives.rb +7 -0
- data/lib/yard/tags/library.rb +3 -3
- data/lib/yard/tags/types_explainer.rb +2 -1
- data/lib/yard/templates/helpers/base_helper.rb +1 -1
- data/lib/yard/templates/helpers/html_helper.rb +16 -5
- data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +6 -1
- data/lib/yard/templates/helpers/markup/hybrid_markdown.rb +2125 -0
- data/lib/yard/templates/helpers/markup_helper.rb +4 -2
- data/lib/yard/version.rb +1 -1
- data/po/ja.po +82 -82
- data/templates/default/fulldoc/html/full_list.erb +4 -4
- data/templates/default/fulldoc/html/js/app.js +503 -319
- data/templates/default/fulldoc/html/js/full_list.js +310 -212
- data/templates/default/layout/html/headers.erb +1 -1
- data/templates/default/method/html/header.erb +3 -3
- data/templates/default/module/html/defines.erb +3 -3
- data/templates/default/module/html/inherited_methods.erb +1 -0
- data/templates/default/module/html/method_summary.erb +8 -0
- data/templates/default/module/setup.rb +20 -0
- data/templates/default/onefile/html/layout.erb +3 -4
- data/templates/guide/fulldoc/html/js/app.js +57 -26
- data/templates/guide/layout/html/layout.erb +9 -11
- metadata +14 -4
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module YARD
|
|
3
|
+
module Parser
|
|
4
|
+
module RBS
|
|
5
|
+
# Parses RBS (Ruby type signature) files and produces a list of
|
|
6
|
+
# {Statement} objects for post-processing by handlers.
|
|
7
|
+
#
|
|
8
|
+
# RBS is Ruby's official type signature format (introduced in Ruby 3.0).
|
|
9
|
+
# This parser handles: class/module/interface declarations, method
|
|
10
|
+
# signatures, attribute accessors, mixins, and constants.
|
|
11
|
+
#
|
|
12
|
+
# No external gem dependencies are used; the parser is hand-written.
|
|
13
|
+
class RbsParser < YARD::Parser::Base
|
|
14
|
+
# @param source [String] source code to parse
|
|
15
|
+
# @param filename [String] path to the source file
|
|
16
|
+
def initialize(source, filename)
|
|
17
|
+
@source = source
|
|
18
|
+
@filename = filename
|
|
19
|
+
@statements = nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Parses the source and returns self.
|
|
23
|
+
# @return [RbsParser] self
|
|
24
|
+
def parse
|
|
25
|
+
lines = @source.lines.map { |l| l.chomp }
|
|
26
|
+
@statements, = parse_body(lines, 0, false)
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Tokenization is not implemented for RBS.
|
|
31
|
+
def tokenize
|
|
32
|
+
raise NotImplementedError, "RBS parser does not support tokenization"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Array<Statement>] top-level statements for the post-processor
|
|
36
|
+
def enumerator
|
|
37
|
+
@statements
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
# Parse a sequence of lines, returning statements and the index after the last consumed line.
|
|
43
|
+
#
|
|
44
|
+
# @param lines [Array<String>] source lines
|
|
45
|
+
# @param start [Integer] index to start from (0-based)
|
|
46
|
+
# @param stop_at_end [Boolean] when true, stop parsing when we see a bare `end`
|
|
47
|
+
# @return [Array(Array<Statement>, Integer)] [statements, new_index]
|
|
48
|
+
def parse_body(lines, start, stop_at_end)
|
|
49
|
+
statements = []
|
|
50
|
+
i = start
|
|
51
|
+
pending_comments = []
|
|
52
|
+
pending_start_1 = nil # 1-indexed line number of first pending comment
|
|
53
|
+
|
|
54
|
+
while i < lines.length
|
|
55
|
+
raw = lines[i]
|
|
56
|
+
stripped = raw.strip
|
|
57
|
+
|
|
58
|
+
if stripped =~ /\A#(.*)/
|
|
59
|
+
# Comment line – accumulate into pending docstring.
|
|
60
|
+
# Strip at most one leading space (conventional RBS doc style).
|
|
61
|
+
pending_comments << $1.sub(/\A /, '')
|
|
62
|
+
pending_start_1 ||= i + 1
|
|
63
|
+
i += 1
|
|
64
|
+
|
|
65
|
+
elsif stripped.empty?
|
|
66
|
+
# Blank line resets pending comments.
|
|
67
|
+
pending_comments = []
|
|
68
|
+
pending_start_1 = nil
|
|
69
|
+
i += 1
|
|
70
|
+
|
|
71
|
+
elsif stop_at_end && stripped == 'end'
|
|
72
|
+
# End of enclosing block.
|
|
73
|
+
return [statements, i + 1]
|
|
74
|
+
|
|
75
|
+
else
|
|
76
|
+
stmt, i = parse_statement(lines, i, pending_comments, pending_start_1)
|
|
77
|
+
statements << stmt if stmt
|
|
78
|
+
pending_comments = []
|
|
79
|
+
pending_start_1 = nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
[statements, i]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def strip_inline_comment(line)
|
|
87
|
+
in_single = false
|
|
88
|
+
in_double = false
|
|
89
|
+
escaped = false
|
|
90
|
+
|
|
91
|
+
line.each_char.with_index do |char, index|
|
|
92
|
+
if escaped
|
|
93
|
+
escaped = false
|
|
94
|
+
next
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
case char
|
|
98
|
+
when "\\"
|
|
99
|
+
escaped = true if in_single || in_double
|
|
100
|
+
when "'"
|
|
101
|
+
in_single = !in_single unless in_double
|
|
102
|
+
when '"'
|
|
103
|
+
in_double = !in_double unless in_single
|
|
104
|
+
when '#'
|
|
105
|
+
return line[0...index].rstrip unless in_single || in_double
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
line.rstrip
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def sanitized_statement_lines(lines, start_index)
|
|
113
|
+
overrides = { start_index => strip_inline_comment(lines[start_index]) }
|
|
114
|
+
|
|
115
|
+
j = start_index + 1
|
|
116
|
+
while j < lines.length && lines[j].lstrip.start_with?('|')
|
|
117
|
+
overrides[j] = strip_inline_comment(lines[j])
|
|
118
|
+
j += 1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
overrides
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Dispatch a single declaration line.
|
|
125
|
+
def parse_statement(lines, i, comments, comment_start_1)
|
|
126
|
+
sanitized = sanitized_statement_lines(lines, i)
|
|
127
|
+
stripped = sanitized.fetch(i, lines[i]).strip
|
|
128
|
+
line_num = i + 1 # 1-indexed
|
|
129
|
+
|
|
130
|
+
docs = comments.empty? ? nil : comments.join("\n")
|
|
131
|
+
crange = comment_start_1 ? (comment_start_1)..(line_num - 1) : nil
|
|
132
|
+
|
|
133
|
+
case stripped
|
|
134
|
+
when /\Aclass\s/
|
|
135
|
+
parse_namespace(:class, lines, i, docs, crange)
|
|
136
|
+
when /\Amodule\s/
|
|
137
|
+
parse_namespace(:module, lines, i, docs, crange)
|
|
138
|
+
when /\Ainterface\s/
|
|
139
|
+
parse_namespace(:interface, lines, i, docs, crange)
|
|
140
|
+
when /\Adef\s/
|
|
141
|
+
parse_method_def(sanitized, lines, i, docs, crange)
|
|
142
|
+
when /\Aattr_reader\s/
|
|
143
|
+
parse_attr(:attr_reader, lines, i, docs, crange)
|
|
144
|
+
when /\Aattr_writer\s/
|
|
145
|
+
parse_attr(:attr_writer, lines, i, docs, crange)
|
|
146
|
+
when /\Aattr_accessor\s/
|
|
147
|
+
parse_attr(:attr_accessor, lines, i, docs, crange)
|
|
148
|
+
when /\A(include|extend|prepend)\s+(\S+)/
|
|
149
|
+
kind = $1.to_sym
|
|
150
|
+
name = $2.delete(';')
|
|
151
|
+
stmt = Statement.new(
|
|
152
|
+
:type => kind,
|
|
153
|
+
:name => name,
|
|
154
|
+
:mixin_name => name,
|
|
155
|
+
:line => line_num,
|
|
156
|
+
:source => stripped,
|
|
157
|
+
:comments => docs,
|
|
158
|
+
:comments_range => crange
|
|
159
|
+
)
|
|
160
|
+
[stmt, i + 1]
|
|
161
|
+
when /\Aalias\s+(\S+)\s+(\S+)/
|
|
162
|
+
stmt = Statement.new(
|
|
163
|
+
:type => :alias,
|
|
164
|
+
:name => $1,
|
|
165
|
+
:line => line_num,
|
|
166
|
+
:source => stripped,
|
|
167
|
+
:comments => docs,
|
|
168
|
+
:comments_range => crange
|
|
169
|
+
)
|
|
170
|
+
[stmt, i + 1]
|
|
171
|
+
when /\A(public|private|protected)\s*(\z|#)/
|
|
172
|
+
# Visibility modifier – skip silently.
|
|
173
|
+
[nil, i + 1]
|
|
174
|
+
when /\Aend\s*(\z|#)/
|
|
175
|
+
# Stray `end` – skip.
|
|
176
|
+
[nil, i + 1]
|
|
177
|
+
when /\Atype\s/
|
|
178
|
+
# Type alias declaration – nothing to document.
|
|
179
|
+
[nil, i + 1]
|
|
180
|
+
else
|
|
181
|
+
# Constant declaration: `NAME: Type`
|
|
182
|
+
if stripped =~ /\A([A-Z][a-zA-Z0-9_]*(?:::[A-Z][a-zA-Z0-9_]*)*)\s*:\s*(.+)\z/
|
|
183
|
+
stmt = Statement.new(
|
|
184
|
+
:type => :constant,
|
|
185
|
+
:name => $1,
|
|
186
|
+
:attr_rbs_type => $2.strip,
|
|
187
|
+
:line => line_num,
|
|
188
|
+
:source => stripped,
|
|
189
|
+
:comments => docs,
|
|
190
|
+
:comments_range => crange
|
|
191
|
+
)
|
|
192
|
+
[stmt, i + 1]
|
|
193
|
+
else
|
|
194
|
+
[nil, i + 1]
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def parse_namespace(type, lines, i, docs, crange)
|
|
200
|
+
# Strip trailing inline comment from the declaration line.
|
|
201
|
+
decl = lines[i].strip.sub(/\s*#.*\z/, '')
|
|
202
|
+
line_num = i + 1
|
|
203
|
+
|
|
204
|
+
name = nil
|
|
205
|
+
superclass = nil
|
|
206
|
+
|
|
207
|
+
case type
|
|
208
|
+
when :class
|
|
209
|
+
# class Foo[T] < Bar[String]
|
|
210
|
+
if decl =~ /\Aclass\s+([^\s<\[]+)(\[[^\]]*\])?(?:\s*<\s*(.+))?\z/
|
|
211
|
+
name = $1.strip
|
|
212
|
+
superclass = $3 ? $3.strip : nil
|
|
213
|
+
# Strip generic params from superclass, e.g. "Array[String]" -> "Array"
|
|
214
|
+
superclass.sub!(/\[.*\]\z/, '') if superclass
|
|
215
|
+
else
|
|
216
|
+
return [nil, i + 1]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
when :module
|
|
220
|
+
# module Foo[T] : SelfType
|
|
221
|
+
if decl =~ /\Amodule\s+([^\s\[(:]+)/
|
|
222
|
+
name = $1.strip
|
|
223
|
+
else
|
|
224
|
+
return [nil, i + 1]
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
when :interface
|
|
228
|
+
# interface _Foo[T]
|
|
229
|
+
if decl =~ /\Ainterface\s+([^\s\[]+)/
|
|
230
|
+
name = $1.strip
|
|
231
|
+
else
|
|
232
|
+
return [nil, i + 1]
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
children, new_i = parse_body(lines, i + 1, true)
|
|
237
|
+
source = lines[i...new_i].join("\n")
|
|
238
|
+
|
|
239
|
+
stmt = Statement.new(
|
|
240
|
+
:type => type,
|
|
241
|
+
:name => name,
|
|
242
|
+
:superclass => superclass,
|
|
243
|
+
:line => line_num,
|
|
244
|
+
:source => source,
|
|
245
|
+
:comments => docs,
|
|
246
|
+
:comments_range => crange,
|
|
247
|
+
:block => children
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
[stmt, new_i]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def parse_method_def(sanitized, lines, i, docs, crange)
|
|
254
|
+
stripped = sanitized.fetch(i, lines[i]).strip
|
|
255
|
+
line_num = i + 1
|
|
256
|
+
|
|
257
|
+
# def method_name: overload1
|
|
258
|
+
# | overload2
|
|
259
|
+
# Also handles: def self.method_name: ...
|
|
260
|
+
unless stripped =~ /\Adef\s+(self\.)?(\S+?)\s*:\s*(.*)\z/
|
|
261
|
+
return [nil, i + 1]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
is_class_side = !$1.nil?
|
|
265
|
+
meth_name = $2
|
|
266
|
+
first_sig = $3.strip
|
|
267
|
+
|
|
268
|
+
sigs = [first_sig]
|
|
269
|
+
j = i + 1
|
|
270
|
+
|
|
271
|
+
# Collect `| overload` continuation lines.
|
|
272
|
+
while j < lines.length
|
|
273
|
+
cont = sanitized.fetch(j, lines[j]).strip
|
|
274
|
+
if cont =~ /\A\|\s*(.*)\z/
|
|
275
|
+
sigs << $1.strip
|
|
276
|
+
j += 1
|
|
277
|
+
else
|
|
278
|
+
break
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
stmt = Statement.new(
|
|
283
|
+
:type => :method_def,
|
|
284
|
+
:name => meth_name,
|
|
285
|
+
:line => line_num,
|
|
286
|
+
:source => lines[i...j].join("\n"),
|
|
287
|
+
:comments => docs,
|
|
288
|
+
:comments_range => crange,
|
|
289
|
+
:signatures => sigs,
|
|
290
|
+
:visibility => is_class_side ? :class : :instance
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
[stmt, j]
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def parse_attr(type, lines, i, docs, crange)
|
|
297
|
+
stripped = strip_inline_comment(lines[i]).strip
|
|
298
|
+
line_num = i + 1
|
|
299
|
+
keyword = type.to_s
|
|
300
|
+
|
|
301
|
+
# attr_reader [self.] name : Type
|
|
302
|
+
if stripped =~ /\A#{Regexp.escape(keyword)}\s+(self\.)?(\w+)\s*:\s*(.*)\z/
|
|
303
|
+
is_class = !$1.nil?
|
|
304
|
+
attr_name = $2
|
|
305
|
+
attr_type = $3.strip
|
|
306
|
+
|
|
307
|
+
stmt = Statement.new(
|
|
308
|
+
:type => type,
|
|
309
|
+
:name => attr_name,
|
|
310
|
+
:attr_rbs_type => attr_type,
|
|
311
|
+
:line => line_num,
|
|
312
|
+
:source => stripped,
|
|
313
|
+
:comments => docs,
|
|
314
|
+
:comments_range => crange,
|
|
315
|
+
:visibility => is_class ? :class : :instance
|
|
316
|
+
)
|
|
317
|
+
[stmt, i + 1]
|
|
318
|
+
else
|
|
319
|
+
[nil, i + 1]
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module YARD
|
|
3
|
+
module Parser
|
|
4
|
+
module RBS
|
|
5
|
+
# Represents a single parsed declaration from an RBS file.
|
|
6
|
+
# Each Statement may have a block of child statements for
|
|
7
|
+
# namespace declarations (class, module, interface).
|
|
8
|
+
class Statement
|
|
9
|
+
# @return [Symbol] declaration type:
|
|
10
|
+
# :class, :module, :interface, :method_def,
|
|
11
|
+
# :attr_reader, :attr_writer, :attr_accessor,
|
|
12
|
+
# :include, :extend, :prepend, :constant, :alias
|
|
13
|
+
attr_reader :type
|
|
14
|
+
|
|
15
|
+
# @return [String] the declaration name
|
|
16
|
+
attr_reader :name
|
|
17
|
+
|
|
18
|
+
# @return [String, nil] the superclass name (for :class)
|
|
19
|
+
attr_reader :superclass
|
|
20
|
+
|
|
21
|
+
# @return [Integer] 1-indexed line number of this statement
|
|
22
|
+
attr_reader :line
|
|
23
|
+
|
|
24
|
+
# @return [String] raw source text of the statement
|
|
25
|
+
attr_reader :source
|
|
26
|
+
|
|
27
|
+
# @return [String, nil] adjacent comment text (the docstring)
|
|
28
|
+
attr_reader :comments
|
|
29
|
+
|
|
30
|
+
# @return [Range, nil] line range of the preceding comments
|
|
31
|
+
attr_reader :comments_range
|
|
32
|
+
|
|
33
|
+
# @return [false] RBS files don't use ## hash-flag comments
|
|
34
|
+
attr_reader :comments_hash_flag
|
|
35
|
+
|
|
36
|
+
# @return [Array<Statement>] child statements for namespace blocks
|
|
37
|
+
attr_reader :block
|
|
38
|
+
|
|
39
|
+
# @return [Array<String>] RBS type signature strings for :method_def
|
|
40
|
+
# Each element is one overload (e.g. "(String name) -> Integer")
|
|
41
|
+
attr_reader :signatures
|
|
42
|
+
|
|
43
|
+
# @return [String, nil] mixin name for :include/:extend/:prepend
|
|
44
|
+
attr_reader :mixin_name
|
|
45
|
+
|
|
46
|
+
# @return [String, nil] RBS type annotation for attrs and constants
|
|
47
|
+
attr_reader :attr_rbs_type
|
|
48
|
+
|
|
49
|
+
# @return [Symbol, nil] :class or :instance scope hint from parser
|
|
50
|
+
attr_reader :visibility
|
|
51
|
+
|
|
52
|
+
def initialize(attrs = {})
|
|
53
|
+
@type = attrs[:type]
|
|
54
|
+
@name = attrs[:name]
|
|
55
|
+
@superclass = attrs[:superclass]
|
|
56
|
+
@line = attrs[:line] || 1
|
|
57
|
+
@source = attrs[:source] || ''
|
|
58
|
+
@comments = attrs[:comments]
|
|
59
|
+
@comments_range = attrs[:comments_range]
|
|
60
|
+
@comments_hash_flag = false
|
|
61
|
+
@block = attrs[:block] || []
|
|
62
|
+
@signatures = attrs[:signatures] || []
|
|
63
|
+
@mixin_name = attrs[:mixin_name]
|
|
64
|
+
@attr_rbs_type = attrs[:attr_rbs_type]
|
|
65
|
+
@visibility = attrs[:visibility]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @return [String] a textual snippet used in error messages
|
|
69
|
+
def show
|
|
70
|
+
source
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -10,7 +10,25 @@
|
|
|
10
10
|
#
|
|
11
11
|
#
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
begin
|
|
14
|
+
require "irb/notifier"
|
|
15
|
+
rescue LoadError
|
|
16
|
+
module IRB
|
|
17
|
+
module DebugLogger
|
|
18
|
+
def self.pp(*args) end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module Notifier
|
|
22
|
+
D_NOMSG = 0x00
|
|
23
|
+
def self.def_notifier(*args) self end
|
|
24
|
+
def self.pp(*args) end
|
|
25
|
+
def self.exec_if(*args, &block) end
|
|
26
|
+
def self.printf(*args) end
|
|
27
|
+
def self.puts(*args) end
|
|
28
|
+
def self.level=(value) end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
14
32
|
|
|
15
33
|
# @private
|
|
16
34
|
module IRB
|
|
@@ -244,6 +244,7 @@ module YARD
|
|
|
244
244
|
sstart = child_node.source_range.first
|
|
245
245
|
else
|
|
246
246
|
lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1])
|
|
247
|
+
(@map[:rbrace] ||= []).shift if map && MAPPINGS[node.type] == :lbrace
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
raise "Cannot determine start of node #{node} around #{file}:#{lineno}" if lstart.nil? || sstart.nil?
|
|
@@ -308,7 +309,7 @@ module YARD
|
|
|
308
309
|
@heredoc_tokens << [token, data, [lineno, charno]]
|
|
309
310
|
|
|
310
311
|
# fix ripper encoding of heredoc bug
|
|
311
|
-
# (see
|
|
312
|
+
# (see https://bugs.ruby-lang.org/issues/6200)
|
|
312
313
|
data.force_encoding(file_encoding) if file_encoding
|
|
313
314
|
|
|
314
315
|
@heredoc_state = :ended if token == :heredoc_end
|
|
@@ -336,6 +337,7 @@ module YARD
|
|
|
336
337
|
undef on_aref_field
|
|
337
338
|
undef on_lbracket
|
|
338
339
|
undef on_rbracket
|
|
340
|
+
undef on_rbrace
|
|
339
341
|
undef on_string_literal
|
|
340
342
|
undef on_lambda
|
|
341
343
|
undef on_unary
|
|
@@ -371,6 +373,20 @@ module YARD
|
|
|
371
373
|
visit_event AstNode.new(:hash, args.first || [])
|
|
372
374
|
end
|
|
373
375
|
|
|
376
|
+
# Ruby 3.0+ pattern matching: braced hash patterns ({key: val} syntax) fire
|
|
377
|
+
# on_lbrace and on_rbrace scanner events. The corresponding parser event is
|
|
378
|
+
# on_hshptn (not on_hash), so we must clean up the brace maps to prevent stale
|
|
379
|
+
# entries from corrupting source ranges of later hash literals and brace blocks.
|
|
380
|
+
# Bare hash patterns (key: val without braces) fire no brace scanner events, so
|
|
381
|
+
# we only clean up when @map[:rbrace] confirms a closing brace was scanned.
|
|
382
|
+
def on_hshptn(*args)
|
|
383
|
+
if (@map[:rbrace] ||= []).any?
|
|
384
|
+
(@map[:lbrace] ||= []).pop
|
|
385
|
+
@map[:rbrace].shift
|
|
386
|
+
end
|
|
387
|
+
AstNode.new(:hshptn, args)
|
|
388
|
+
end
|
|
389
|
+
|
|
374
390
|
def on_bare_assoc_hash(*args)
|
|
375
391
|
AstNode.new(:list, args.first)
|
|
376
392
|
end
|
|
@@ -398,8 +414,10 @@ module YARD
|
|
|
398
414
|
|
|
399
415
|
def on_aref_field(*args)
|
|
400
416
|
@map[:lbracket].pop
|
|
401
|
-
|
|
402
|
-
|
|
417
|
+
ll, lc = *@map[:aref].shift
|
|
418
|
+
sr = args.first.source_range.begin..lc
|
|
419
|
+
lr = args.first.line_range.begin..ll
|
|
420
|
+
AstNode.new(:aref_field, args, :char => sr, :line => lr)
|
|
403
421
|
end
|
|
404
422
|
|
|
405
423
|
def on_array(other)
|
|
@@ -420,6 +438,27 @@ module YARD
|
|
|
420
438
|
node
|
|
421
439
|
end
|
|
422
440
|
|
|
441
|
+
# Ruby 3.0+ pattern matching: array patterns (SomeClass[a, b]) and find patterns
|
|
442
|
+
# (SomeClass[*pre, val, *post]) use [...] brackets, which fire on_lbracket and
|
|
443
|
+
# on_rbracket scanner events. The corresponding parser events are on_aryptn/on_fndptn
|
|
444
|
+
# (not on_aref), so we must clean up the bracket maps to prevent stale entries from
|
|
445
|
+
# corrupting source ranges of later array indexing expressions.
|
|
446
|
+
def on_aryptn(*args)
|
|
447
|
+
(@map[:lbracket] ||= []).pop
|
|
448
|
+
(@map[:aref] ||= []).shift
|
|
449
|
+
# Source range is intentionally not set; no handler is registered for
|
|
450
|
+
# pattern-match nodes, so they produce no documentation output.
|
|
451
|
+
AstNode.new(:aryptn, args)
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def on_fndptn(*args)
|
|
455
|
+
(@map[:lbracket] ||= []).pop
|
|
456
|
+
(@map[:aref] ||= []).shift
|
|
457
|
+
# Source range is intentionally not set; no handler is registered for
|
|
458
|
+
# pattern-match nodes, so they produce no documentation output.
|
|
459
|
+
AstNode.new(:fndptn, args)
|
|
460
|
+
end
|
|
461
|
+
|
|
423
462
|
def on_lbracket(tok)
|
|
424
463
|
(@map[:lbracket] ||= []) << [lineno, charno]
|
|
425
464
|
visit_ns_token(:lbracket, tok, false)
|
|
@@ -430,6 +469,13 @@ module YARD
|
|
|
430
469
|
visit_ns_token(:rbracket, tok, false)
|
|
431
470
|
end
|
|
432
471
|
|
|
472
|
+
# Maintained explicitly (unlike on_lbracket/on_rbracket) so on_hshptn can
|
|
473
|
+
# distinguish braced from bare hash patterns in Ruby 3.0+ pattern matching.
|
|
474
|
+
def on_rbrace(tok)
|
|
475
|
+
(@map[:rbrace] ||= []) << [lineno, charno]
|
|
476
|
+
visit_ns_token(:rbrace, tok, false)
|
|
477
|
+
end
|
|
478
|
+
|
|
433
479
|
def on_dyna_symbol(sym)
|
|
434
480
|
rng = if sym.source_range.to_a.size == 0 # rubocop:disable Style/ZeroLengthPredicate
|
|
435
481
|
(sym.source_range.begin - 3)...sym.source_range.end
|
|
@@ -623,6 +669,7 @@ module YARD
|
|
|
623
669
|
alias compile_error on_parse_error
|
|
624
670
|
|
|
625
671
|
def comment_starts_line?(charno)
|
|
672
|
+
return true if @source[charno] == "\n"
|
|
626
673
|
(charno - 1).downto(0) do |i|
|
|
627
674
|
ch = @source[i]
|
|
628
675
|
break if ch == "\n"
|
|
@@ -700,6 +747,11 @@ module YARD
|
|
|
700
747
|
def add_comment(line, node = nil, before_node = nil, into = false)
|
|
701
748
|
comment = @comments[line]
|
|
702
749
|
source_range = @comments_range[line]
|
|
750
|
+
if comment && source_range
|
|
751
|
+
source = @source[source_range]
|
|
752
|
+
last_line = source.lines.to_a.last
|
|
753
|
+
return if last_line && last_line =~ /^\s*\#-\s*$/
|
|
754
|
+
end
|
|
703
755
|
line_range = ((line - comment.count("\n"))..line)
|
|
704
756
|
if node.nil?
|
|
705
757
|
node = CommentNode.new(:comment, [comment], :line => line_range, :char => source_range)
|
|
@@ -67,7 +67,7 @@ module YARD
|
|
|
67
67
|
|
|
68
68
|
# The default glob of files to be parsed.
|
|
69
69
|
# @since 0.9.0
|
|
70
|
-
DEFAULT_PATH_GLOB = ["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp,rb}"]
|
|
70
|
+
DEFAULT_PATH_GLOB = ["{lib,app}/**/*.{rb,rbs}", "sig/**/*.rbs", "ext/**/*.{c,cc,cxx,cpp,rb}"]
|
|
71
71
|
|
|
72
72
|
# Byte order marks for various encodings
|
|
73
73
|
# @since 0.7.0
|
|
@@ -105,7 +105,7 @@ module YARD
|
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
files = [paths].flatten.
|
|
108
|
-
map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }.
|
|
108
|
+
map {|p| File.directory?(p) ? "#{p}/**/*.{rb,rbs,c,cc,cxx,cpp}" : p }.
|
|
109
109
|
map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten.
|
|
110
110
|
reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }.
|
|
111
111
|
map {|p| p.encoding == Encoding.default_external ? p : p.dup.force_encoding(Encoding.default_external) }
|
|
@@ -379,6 +379,7 @@ module YARD
|
|
|
379
379
|
register_parser_type :ruby, Ruby::RubyParser
|
|
380
380
|
register_parser_type :ruby18, Ruby::Legacy::RubyParser
|
|
381
381
|
register_parser_type :c, C::CParser, ['c', 'cc', 'cxx', 'cpp']
|
|
382
|
+
register_parser_type :rbs, RBS::RbsParser, ['rbs']
|
|
382
383
|
|
|
383
384
|
self.parser_type = :ruby
|
|
384
385
|
|
|
@@ -75,6 +75,13 @@ module YARD
|
|
|
75
75
|
lexical_lookup = 0
|
|
76
76
|
while namespace && !resolved
|
|
77
77
|
resolved = lookup_path_direct(namespace, path, type)
|
|
78
|
+
# Prevent a bare name from resolving back to the namespace we started
|
|
79
|
+
# from when searching through a parent namespace. For example,
|
|
80
|
+
# `include Enumerable` inside `A::Enumerable` would walk up to namespace
|
|
81
|
+
# `A` and match `A::Enumerable`, creating a false self-referential mixin.
|
|
82
|
+
# Only skip when we have already moved to a parent (namespace != orignamespace).
|
|
83
|
+
# See https://github.com/lsegal/yard/issues/1116
|
|
84
|
+
resolved = nil if resolved.equal?(orignamespace) && !namespace.equal?(orignamespace)
|
|
78
85
|
resolved ||= lookup_path_inherited(namespace, path, type) if inheritance
|
|
79
86
|
break if resolved
|
|
80
87
|
namespace = namespace.parent
|
|
@@ -71,7 +71,7 @@ module YARD
|
|
|
71
71
|
# def load_yardoc_from_http
|
|
72
72
|
# Thread.new do
|
|
73
73
|
# # zip/unzip method implementations are not shown
|
|
74
|
-
# download_zip_file("
|
|
74
|
+
# download_zip_file("https://mysite.com/yardocs/#{self}.zip")
|
|
75
75
|
# unzip_file_to("/path/to/yardocs/#{self}")
|
|
76
76
|
# end
|
|
77
77
|
#
|