rdoc 7.2.0 → 8.0.0
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/CONTRIBUTING.md +3 -4
- data/LICENSE.rdoc +4 -0
- data/README.md +43 -2
- data/doc/markup_reference/markdown.md +104 -3
- data/lib/rdoc/code_object/alias.rb +2 -8
- data/lib/rdoc/code_object/any_method.rb +11 -6
- data/lib/rdoc/code_object/attr.rb +11 -6
- data/lib/rdoc/code_object/class_module.rb +62 -32
- data/lib/rdoc/code_object/constant.rb +29 -3
- data/lib/rdoc/code_object/context/section.rb +4 -35
- data/lib/rdoc/code_object/context.rb +39 -34
- data/lib/rdoc/code_object/method_attr.rb +9 -15
- data/lib/rdoc/code_object/mixin.rb +2 -2
- data/lib/rdoc/code_object/top_level.rb +9 -3
- data/lib/rdoc/code_object.rb +2 -4
- data/lib/rdoc/comment.rb +0 -65
- data/lib/rdoc/cross_reference.rb +7 -27
- data/lib/rdoc/encoding.rb +3 -3
- data/lib/rdoc/generator/aliki.rb +17 -0
- data/lib/rdoc/generator/darkfish.rb +12 -6
- data/lib/rdoc/generator/json_index.rb +2 -2
- data/lib/rdoc/generator/markup.rb +56 -31
- data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
- data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_head.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
- data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
- data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
- data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/class.rhtml +56 -46
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +337 -111
- data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/js/aliki.js +20 -18
- data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
- data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
- data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
- data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
- data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
- data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
- data/lib/rdoc/i18n/text.rb +3 -3
- data/lib/rdoc/markdown.kpeg +15 -10
- data/lib/rdoc/markdown.rb +289 -104
- data/lib/rdoc/markup/document.rb +2 -2
- data/lib/rdoc/markup/formatter.rb +24 -34
- data/lib/rdoc/markup/heading.rb +1 -4
- data/lib/rdoc/markup/indented_paragraph.rb +1 -1
- data/lib/rdoc/markup/list.rb +2 -2
- data/lib/rdoc/markup/list_item.rb +2 -2
- data/lib/rdoc/markup/pre_process.rb +0 -25
- data/lib/rdoc/markup/to_ansi.rb +1 -1
- data/lib/rdoc/markup/to_bs.rb +1 -1
- data/lib/rdoc/markup/to_html.rb +131 -53
- data/lib/rdoc/markup/to_html_crossref.rb +97 -71
- data/lib/rdoc/markup/to_html_snippet.rb +5 -5
- data/lib/rdoc/markup/to_joined_paragraph.rb +0 -5
- data/lib/rdoc/markup/to_label.rb +2 -2
- data/lib/rdoc/markup/to_markdown.rb +1 -1
- data/lib/rdoc/markup/to_rdoc.rb +2 -2
- data/lib/rdoc/markup/to_table_of_contents.rb +1 -1
- data/lib/rdoc/markup/to_tt_only.rb +0 -7
- data/lib/rdoc/markup/verbatim.rb +1 -1
- data/lib/rdoc/options.rb +36 -51
- data/lib/rdoc/parser/c.rb +7 -6
- data/lib/rdoc/parser/rbs.rb +275 -0
- data/lib/rdoc/parser/ruby.rb +954 -2066
- data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
- data/lib/rdoc/parser.rb +3 -2
- data/lib/rdoc/rbs_helper.rb +186 -0
- data/lib/rdoc/rdoc.rb +196 -24
- data/lib/rdoc/ri/driver.rb +8 -2
- data/lib/rdoc/ri/paths.rb +1 -1
- data/lib/rdoc/{servlet.rb → ri/servlet.rb} +5 -5
- data/lib/rdoc/ri.rb +4 -3
- data/lib/rdoc/rubygems_hook.rb +11 -11
- data/lib/rdoc/server.rb +460 -0
- data/lib/rdoc/stats.rb +147 -124
- data/lib/rdoc/store.rb +212 -4
- data/lib/rdoc/task.rb +16 -15
- data/lib/rdoc/text.rb +1 -118
- data/lib/rdoc/token_stream.rb +11 -33
- data/lib/rdoc/version.rb +1 -1
- data/lib/rdoc.rb +35 -7
- data/lib/rubygems_plugin.rb +2 -11
- data/rdoc-logo.svg +43 -0
- data/rdoc.gemspec +6 -4
- metadata +35 -18
- data/lib/rdoc/code_object/anon_class.rb +0 -10
- data/lib/rdoc/code_object/ghost_method.rb +0 -6
- data/lib/rdoc/code_object/meta_method.rb +0 -6
- data/lib/rdoc/parser/prism_ruby.rb +0 -1112
- data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
- data/lib/rdoc/parser/ruby_tools.rb +0 -163
data/lib/rdoc/stats.rb
CHANGED
|
@@ -7,6 +7,19 @@ class RDoc::Stats
|
|
|
7
7
|
|
|
8
8
|
include RDoc::Text
|
|
9
9
|
|
|
10
|
+
##
|
|
11
|
+
# Display order for item types in the coverage report
|
|
12
|
+
|
|
13
|
+
TYPE_ORDER = %w[Class Module Constant Attribute Method].freeze
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Message displayed when all items are documented
|
|
17
|
+
|
|
18
|
+
GREAT_JOB_MESSAGE = <<~MSG
|
|
19
|
+
100% documentation!
|
|
20
|
+
Great Job!
|
|
21
|
+
MSG
|
|
22
|
+
|
|
10
23
|
##
|
|
11
24
|
# Output level for the coverage report
|
|
12
25
|
|
|
@@ -39,10 +52,17 @@ class RDoc::Stats
|
|
|
39
52
|
@start = Time.now
|
|
40
53
|
@undoc_params = 0
|
|
41
54
|
|
|
55
|
+
self.verbosity = verbosity
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# Sets the verbosity level, rebuilding the display outputter.
|
|
60
|
+
|
|
61
|
+
def verbosity=(verbosity)
|
|
42
62
|
@display = case verbosity
|
|
43
|
-
when 0 then Quiet.new num_files
|
|
44
|
-
when 1 then Normal.new num_files
|
|
45
|
-
else Verbose.new num_files
|
|
63
|
+
when 0 then Quiet.new @num_files
|
|
64
|
+
when 1 then Normal.new @num_files
|
|
65
|
+
else Verbose.new @num_files
|
|
46
66
|
end
|
|
47
67
|
end
|
|
48
68
|
|
|
@@ -186,18 +206,6 @@ class RDoc::Stats
|
|
|
186
206
|
@fully_documented
|
|
187
207
|
end
|
|
188
208
|
|
|
189
|
-
##
|
|
190
|
-
# A report that says you did a great job!
|
|
191
|
-
|
|
192
|
-
def great_job
|
|
193
|
-
report = RDoc::Markup::Document.new
|
|
194
|
-
|
|
195
|
-
report << RDoc::Markup::Paragraph.new('100% documentation!')
|
|
196
|
-
report << RDoc::Markup::Paragraph.new('Great Job!')
|
|
197
|
-
|
|
198
|
-
report
|
|
199
|
-
end
|
|
200
|
-
|
|
201
209
|
##
|
|
202
210
|
# Calculates the percentage of items documented.
|
|
203
211
|
|
|
@@ -223,48 +231,55 @@ class RDoc::Stats
|
|
|
223
231
|
if @coverage_level.zero? then
|
|
224
232
|
calculate
|
|
225
233
|
|
|
226
|
-
return
|
|
234
|
+
return GREAT_JOB_MESSAGE if @num_items == @doc_items
|
|
227
235
|
end
|
|
228
236
|
|
|
229
|
-
|
|
237
|
+
items, empty_classes = collect_undocumented_items
|
|
230
238
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
report << RDoc::Markup::BlankLine.new
|
|
234
|
-
|
|
235
|
-
ucm.sort.each do |cm|
|
|
236
|
-
body = report_class_module(cm) {
|
|
237
|
-
[
|
|
238
|
-
report_constants(cm),
|
|
239
|
-
report_attributes(cm),
|
|
240
|
-
report_methods(cm),
|
|
241
|
-
].compact
|
|
242
|
-
}
|
|
239
|
+
if @coverage_level > 0 then
|
|
240
|
+
calculate
|
|
243
241
|
|
|
244
|
-
|
|
242
|
+
return GREAT_JOB_MESSAGE if @num_items == @doc_items
|
|
245
243
|
end
|
|
246
244
|
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
report = +""
|
|
246
|
+
report << "The following items are not documented:\n\n"
|
|
249
247
|
|
|
250
|
-
|
|
248
|
+
# Referenced-but-empty classes
|
|
249
|
+
empty_classes.each do |cm|
|
|
250
|
+
report << "#{cm.full_name} is referenced but empty.\n"
|
|
251
|
+
report << "It probably came from another project. I'm sorry I'm holding it against you.\n\n"
|
|
251
252
|
end
|
|
252
253
|
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
# Group items by file, then by type
|
|
255
|
+
by_file = items.group_by { |item| item[:file] }
|
|
255
256
|
|
|
256
|
-
|
|
257
|
-
|
|
257
|
+
by_file.sort_by { |file, _| file }.each do |file, file_items|
|
|
258
|
+
report << "#{file}:\n"
|
|
258
259
|
|
|
259
|
-
|
|
260
|
-
return if cm.attributes.empty?
|
|
260
|
+
by_type = file_items.group_by { |item| item[:type] }
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
TYPE_ORDER.each do |type|
|
|
263
|
+
next unless by_type[type]
|
|
264
|
+
|
|
265
|
+
report << " #{type}:\n"
|
|
266
|
+
|
|
267
|
+
sorted = by_type[type].sort_by { |item| [item[:line] || 0, item[:name]] }
|
|
268
|
+
name_width = sorted.reduce(0) { |max, item| item[:line] && item[:name].length > max ? item[:name].length : max }
|
|
269
|
+
|
|
270
|
+
sorted.each do |item|
|
|
271
|
+
if item[:line]
|
|
272
|
+
report << " %-*s %s:%d\n" % [name_width, item[:name], item[:file], item[:line]]
|
|
273
|
+
else
|
|
274
|
+
report << " #{item[:name]}\n"
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
if item[:undoc_params]
|
|
278
|
+
report << " Undocumented params: #{item[:undoc_params].join(', ')}\n"
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
263
282
|
|
|
264
|
-
cm.attributes.each do |attr|
|
|
265
|
-
next if attr.documented?
|
|
266
|
-
line = attr.line ? ":#{attr.line}" : nil
|
|
267
|
-
report << " #{attr.definition} :#{attr.name} # in file #{attr.file.full_name}#{line}\n"
|
|
268
283
|
report << "\n"
|
|
269
284
|
end
|
|
270
285
|
|
|
@@ -272,115 +287,128 @@ class RDoc::Stats
|
|
|
272
287
|
end
|
|
273
288
|
|
|
274
289
|
##
|
|
275
|
-
#
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return unless cm.display?
|
|
280
|
-
|
|
281
|
-
report = RDoc::Markup::Document.new
|
|
290
|
+
# Collects all undocumented items across all classes and modules.
|
|
291
|
+
# Returns [items, empty_classes] where items is an Array of Hashes
|
|
292
|
+
# with keys :type, :name, :file, :line, and empty_classes is an
|
|
293
|
+
# Array of ClassModule objects that are referenced but have no files.
|
|
282
294
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
295
|
+
def collect_undocumented_items
|
|
296
|
+
empty_classes = []
|
|
297
|
+
items = []
|
|
286
298
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
documented = true
|
|
290
|
-
klass = RDoc::Markup::Verbatim.new("#{cm.definition} # is documented\n")
|
|
291
|
-
else
|
|
292
|
-
report << RDoc::Markup::Paragraph.new('In files:')
|
|
299
|
+
@store.unique_classes_and_modules.each do |class_module|
|
|
300
|
+
next unless class_module.display?
|
|
293
301
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
para = RDoc::Markup::Paragraph.new file.full_name
|
|
298
|
-
list << RDoc::Markup::ListItem.new(nil, para)
|
|
302
|
+
if class_module.in_files.empty?
|
|
303
|
+
empty_classes << class_module
|
|
304
|
+
next
|
|
299
305
|
end
|
|
300
306
|
|
|
301
|
-
|
|
302
|
-
|
|
307
|
+
unless class_module.documented? || class_module.full_name == 'Object'
|
|
308
|
+
collect_undocumented_class_module(class_module, items)
|
|
309
|
+
end
|
|
303
310
|
|
|
304
|
-
|
|
311
|
+
collect_undocumented_constants(class_module, items)
|
|
312
|
+
collect_undocumented_attributes(class_module, items)
|
|
313
|
+
collect_undocumented_methods(class_module, items)
|
|
305
314
|
end
|
|
306
315
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
body = yield.flatten # HACK remove #flatten
|
|
310
|
-
|
|
311
|
-
if body.empty? then
|
|
312
|
-
return if documented
|
|
316
|
+
[items, empty_classes]
|
|
317
|
+
end
|
|
313
318
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
319
|
+
##
|
|
320
|
+
# Collects undocumented classes or modules from +class_module+ into +items+.
|
|
321
|
+
# Reopened classes/modules are reported in every file they appear in.
|
|
322
|
+
|
|
323
|
+
def collect_undocumented_class_module(class_module, items)
|
|
324
|
+
class_module.in_files.map(&:full_name).uniq.each do |file|
|
|
325
|
+
items << {
|
|
326
|
+
type: class_module.type.capitalize,
|
|
327
|
+
name: class_module.full_name,
|
|
328
|
+
file: file,
|
|
329
|
+
line: nil,
|
|
330
|
+
}
|
|
317
331
|
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
##
|
|
335
|
+
# Collects undocumented constants from +class_module+ into +items+.
|
|
318
336
|
|
|
319
|
-
|
|
337
|
+
def collect_undocumented_constants(class_module, items)
|
|
338
|
+
class_module.constants.each do |constant|
|
|
339
|
+
next unless constant.display?
|
|
340
|
+
next if constant.documented? || constant.is_alias_for
|
|
320
341
|
|
|
321
|
-
|
|
342
|
+
file = constant.file&.full_name
|
|
343
|
+
next unless file
|
|
322
344
|
|
|
323
|
-
|
|
345
|
+
items << {
|
|
346
|
+
type: "Constant",
|
|
347
|
+
name: constant.full_name,
|
|
348
|
+
file: file,
|
|
349
|
+
line: constant.line,
|
|
350
|
+
}
|
|
351
|
+
end
|
|
324
352
|
end
|
|
325
353
|
|
|
326
354
|
##
|
|
327
|
-
#
|
|
355
|
+
# Collects undocumented attributes from +class_module+ into +items+.
|
|
328
356
|
|
|
329
|
-
def
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
357
|
+
def collect_undocumented_attributes(class_module, items)
|
|
358
|
+
class_module.attributes.each do |attr|
|
|
359
|
+
next unless attr.display?
|
|
360
|
+
next if attr.documented?
|
|
333
361
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
# figure out what to do here
|
|
337
|
-
next if constant.documented? || constant.is_alias_for
|
|
362
|
+
file = attr.file&.full_name
|
|
363
|
+
next unless file
|
|
338
364
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
365
|
+
scope = attr.singleton ? "." : "#"
|
|
366
|
+
items << {
|
|
367
|
+
type: "Attribute",
|
|
368
|
+
name: "#{class_module.full_name}#{scope}#{attr.name}",
|
|
369
|
+
file: file,
|
|
370
|
+
line: attr.line,
|
|
371
|
+
}
|
|
343
372
|
end
|
|
344
|
-
|
|
345
|
-
report
|
|
346
373
|
end
|
|
347
374
|
|
|
348
375
|
##
|
|
349
|
-
#
|
|
376
|
+
# Collects undocumented methods from +class_module+ into +items+.
|
|
377
|
+
# At coverage level > 0, also counts undocumented parameters.
|
|
350
378
|
|
|
351
|
-
def
|
|
352
|
-
|
|
379
|
+
def collect_undocumented_methods(class_module, items)
|
|
380
|
+
class_module.each_method do |method|
|
|
381
|
+
next unless method.display?
|
|
382
|
+
next if method.documented? && @coverage_level.zero?
|
|
353
383
|
|
|
354
|
-
|
|
384
|
+
undoc_param_names = nil
|
|
355
385
|
|
|
356
|
-
|
|
357
|
-
next if method.documented? and @coverage_level.zero?
|
|
358
|
-
|
|
359
|
-
if @coverage_level > 0 then
|
|
386
|
+
if @coverage_level > 0
|
|
360
387
|
params, undoc = undoc_params method
|
|
361
|
-
|
|
362
388
|
@num_params += params
|
|
363
389
|
|
|
364
|
-
unless undoc.empty?
|
|
390
|
+
unless undoc.empty?
|
|
365
391
|
@undoc_params += undoc.length
|
|
366
|
-
|
|
367
|
-
undoc = undoc.map do |param| "+#{param}+" end
|
|
368
|
-
param_report = " # #{undoc.join ', '} is not documented\n"
|
|
392
|
+
undoc_param_names = undoc
|
|
369
393
|
end
|
|
370
394
|
end
|
|
371
395
|
|
|
372
|
-
next if method.documented?
|
|
396
|
+
next if method.documented? && !undoc_param_names
|
|
373
397
|
|
|
374
|
-
|
|
375
|
-
|
|
398
|
+
file = method.file&.full_name
|
|
399
|
+
next unless file
|
|
376
400
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
401
|
+
scope = method.singleton ? "." : "#"
|
|
402
|
+
item = {
|
|
403
|
+
type: "Method",
|
|
404
|
+
name: "#{class_module.full_name}#{scope}#{method.name}",
|
|
405
|
+
file: file,
|
|
406
|
+
line: method.line,
|
|
407
|
+
}
|
|
408
|
+
item[:undoc_params] = undoc_param_names if undoc_param_names
|
|
382
409
|
|
|
383
|
-
|
|
410
|
+
items << item
|
|
411
|
+
end
|
|
384
412
|
end
|
|
385
413
|
|
|
386
414
|
##
|
|
@@ -400,12 +428,10 @@ class RDoc::Stats
|
|
|
400
428
|
@undoc_params,
|
|
401
429
|
].max.to_s.length
|
|
402
430
|
|
|
403
|
-
report =
|
|
431
|
+
report = +""
|
|
404
432
|
|
|
405
433
|
report << "Files: %*d\n" % [num_width, @num_files]
|
|
406
|
-
|
|
407
434
|
report << "\n"
|
|
408
|
-
|
|
409
435
|
report << "Classes: %*d (%*d undocumented)\n" % [
|
|
410
436
|
num_width, @num_classes, undoc_width, @undoc_classes]
|
|
411
437
|
report << "Modules: %*d (%*d undocumented)\n" % [
|
|
@@ -419,17 +445,14 @@ class RDoc::Stats
|
|
|
419
445
|
report << "Parameters: %*d (%*d undocumented)\n" % [
|
|
420
446
|
num_width, @num_params, undoc_width, @undoc_params] if
|
|
421
447
|
@coverage_level > 0
|
|
422
|
-
|
|
423
448
|
report << "\n"
|
|
424
|
-
|
|
425
449
|
report << "Total: %*d (%*d undocumented)\n" % [
|
|
426
450
|
num_width, @num_items, undoc_width, @undoc_items]
|
|
427
|
-
|
|
428
451
|
report << "%6.2f%% documented\n" % percent_doc
|
|
429
452
|
report << "\n"
|
|
430
453
|
report << "Elapsed: %0.1fs\n" % (Time.now - @start)
|
|
431
454
|
|
|
432
|
-
|
|
455
|
+
report
|
|
433
456
|
end
|
|
434
457
|
|
|
435
458
|
##
|
data/lib/rdoc/store.rb
CHANGED
|
@@ -193,6 +193,121 @@ class RDoc::Store
|
|
|
193
193
|
top_level
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
+
##
|
|
197
|
+
# Removes a file and its classes/modules from the store. Used by the
|
|
198
|
+
# live-reloading server when a source file is deleted.
|
|
199
|
+
#
|
|
200
|
+
# Note: this does not handle reopened classes correctly. If a class is
|
|
201
|
+
# defined across multiple files (e.g. +Foo+ in both +a.rb+ and +b.rb+),
|
|
202
|
+
# deleting one file removes the entire class from the store — including
|
|
203
|
+
# the parts contributed by the other file. Saving the remaining file
|
|
204
|
+
# triggers a re-parse that restores it.
|
|
205
|
+
|
|
206
|
+
def remove_file(relative_name)
|
|
207
|
+
top_level = @files_hash.delete(relative_name)
|
|
208
|
+
@text_files_hash.delete(relative_name)
|
|
209
|
+
@c_class_variables.delete(relative_name)
|
|
210
|
+
@c_singleton_class_variables.delete(relative_name)
|
|
211
|
+
return unless top_level
|
|
212
|
+
|
|
213
|
+
remove_classes_and_modules(top_level.classes_or_modules)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
##
|
|
217
|
+
# Removes a file's contributions (methods, constants, comments, etc.)
|
|
218
|
+
# from its classes and modules. If no other files contribute to a
|
|
219
|
+
# class or module, it is removed from the store entirely. This
|
|
220
|
+
# prevents duplication when the file is re-parsed while preserving
|
|
221
|
+
# shared namespaces like +RDoc+ that span many files.
|
|
222
|
+
|
|
223
|
+
def clear_file_contributions(relative_name, keep_position: false)
|
|
224
|
+
top_level = @files_hash[relative_name]
|
|
225
|
+
return unless top_level
|
|
226
|
+
|
|
227
|
+
top_level.classes_or_modules.each do |cm|
|
|
228
|
+
# Remove methods and attributes contributed by this file
|
|
229
|
+
cm.method_list.reject! { |m| m.file == top_level }
|
|
230
|
+
cm.attributes.reject! { |a| a.file == top_level }
|
|
231
|
+
|
|
232
|
+
# Rebuild methods_hash from remaining methods and attributes
|
|
233
|
+
cm.methods_hash.clear
|
|
234
|
+
cm.method_list.each { |m| cm.methods_hash[m.pretty_name] = m }
|
|
235
|
+
cm.attributes.each { |a| cm.methods_hash[a.pretty_name] = a }
|
|
236
|
+
|
|
237
|
+
# Remove constants contributed by this file
|
|
238
|
+
cm.constants.reject! { |c| c.file == top_level }
|
|
239
|
+
cm.constants_hash.clear
|
|
240
|
+
cm.constants.each { |c| cm.constants_hash[c.name] = c }
|
|
241
|
+
|
|
242
|
+
# Remove includes, extends, and aliases from this file
|
|
243
|
+
cm.includes.reject! { |i| i.file == top_level }
|
|
244
|
+
cm.extends.reject! { |e| e.file == top_level }
|
|
245
|
+
cm.aliases.reject! { |a| a.file == top_level }
|
|
246
|
+
cm.external_aliases.reject! { |a| a.file == top_level }
|
|
247
|
+
|
|
248
|
+
# Clear or remove comment entries from this file
|
|
249
|
+
if cm.is_a?(RDoc::ClassModule)
|
|
250
|
+
if keep_position
|
|
251
|
+
cm.comment_location[top_level] = [] if cm.comment_location.key?(top_level)
|
|
252
|
+
else
|
|
253
|
+
cm.comment_location.delete(top_level)
|
|
254
|
+
end
|
|
255
|
+
cm.rebuild_comment_from_location
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
unless keep_position
|
|
259
|
+
# Remove this file from the class/module's file list
|
|
260
|
+
cm.in_files.delete(top_level)
|
|
261
|
+
|
|
262
|
+
# If no files contribute to this class/module anymore, remove it
|
|
263
|
+
# from the store entirely. This handles file deletion correctly
|
|
264
|
+
# for classes that are only defined in the deleted file, while
|
|
265
|
+
# preserving classes that span multiple files.
|
|
266
|
+
if cm.in_files.empty?
|
|
267
|
+
if cm.is_a?(RDoc::NormalModule)
|
|
268
|
+
@modules_hash.delete(cm.full_name)
|
|
269
|
+
else
|
|
270
|
+
@classes_hash.delete(cm.full_name)
|
|
271
|
+
end
|
|
272
|
+
cm.parent&.classes_hash&.delete(cm.name)
|
|
273
|
+
cm.parent&.modules_hash&.delete(cm.name)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Clear the TopLevel's class/module list to prevent duplicates
|
|
279
|
+
top_level.classes_or_modules.clear
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
##
|
|
283
|
+
# Removes stale empty placeholders left by +clear_file_contributions+ with
|
|
284
|
+
# <tt>keep_position: true</tt>. After re-parsing, a file may no longer
|
|
285
|
+
# define a class it previously contributed to, leaving an empty entry in
|
|
286
|
+
# +comment_location+ and a stale +in_files+ reference. Call this after
|
|
287
|
+
# all re-parsing is complete.
|
|
288
|
+
|
|
289
|
+
def cleanup_stale_contributions
|
|
290
|
+
all_classes_and_modules.each do |cm|
|
|
291
|
+
cm.comment_location.delete_if { |_, comments| comments.empty? }
|
|
292
|
+
cm.rebuild_comment_from_location
|
|
293
|
+
|
|
294
|
+
cm.in_files.select! { |tl| cm.comment_location.key?(tl) ||
|
|
295
|
+
cm.method_list.any? { |m| m.file == tl } ||
|
|
296
|
+
cm.attributes.any? { |a| a.file == tl } ||
|
|
297
|
+
cm.constants.any? { |c| c.file == tl } }
|
|
298
|
+
|
|
299
|
+
if cm.in_files.empty?
|
|
300
|
+
if cm.is_a?(RDoc::NormalModule)
|
|
301
|
+
@modules_hash.delete(cm.full_name)
|
|
302
|
+
else
|
|
303
|
+
@classes_hash.delete(cm.full_name)
|
|
304
|
+
end
|
|
305
|
+
cm.parent&.classes_hash&.delete(cm.name)
|
|
306
|
+
cm.parent&.modules_hash&.delete(cm.name)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
196
311
|
##
|
|
197
312
|
# Make sure any references to C variable names are resolved to the corresponding class.
|
|
198
313
|
#
|
|
@@ -206,11 +321,11 @@ class RDoc::Store
|
|
|
206
321
|
end
|
|
207
322
|
|
|
208
323
|
##
|
|
209
|
-
#
|
|
324
|
+
# Caches +relative_name+ in the text files hash, if it is a text file.
|
|
210
325
|
|
|
211
|
-
def
|
|
212
|
-
if top_level = @files_hash[
|
|
213
|
-
@text_files_hash[
|
|
326
|
+
def cache_text_file(relative_name)
|
|
327
|
+
if top_level = @files_hash[relative_name]
|
|
328
|
+
@text_files_hash[relative_name] = top_level if top_level.text?
|
|
214
329
|
end
|
|
215
330
|
end
|
|
216
331
|
|
|
@@ -228,6 +343,86 @@ class RDoc::Store
|
|
|
228
343
|
@classes_hash.values + @modules_hash.values
|
|
229
344
|
end
|
|
230
345
|
|
|
346
|
+
##
|
|
347
|
+
# Returns a hash mapping class/module names to their paths, for use
|
|
348
|
+
# by type signature linking. Maps both qualified names (Foo::Bar) and
|
|
349
|
+
# unambiguous unqualified names (Bar). Ambiguous unqualified names
|
|
350
|
+
# (where multiple classes share the same name) are excluded to avoid
|
|
351
|
+
# wrong links. Cached after first call.
|
|
352
|
+
|
|
353
|
+
##
|
|
354
|
+
# Invalidates the cached type name lookup. Server mode calls this after
|
|
355
|
+
# re-parsing changes the set of classes and modules.
|
|
356
|
+
|
|
357
|
+
def invalidate_type_name_lookup # :nodoc:
|
|
358
|
+
@type_name_lookup = nil
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def type_name_lookup
|
|
362
|
+
@type_name_lookup ||= begin
|
|
363
|
+
lookup = {}
|
|
364
|
+
unqualified_names = {}
|
|
365
|
+
ambiguous_names = {}
|
|
366
|
+
all_classes_and_modules.each do |cm|
|
|
367
|
+
lookup[cm.full_name] = cm.path
|
|
368
|
+
unqualified_name = cm.name
|
|
369
|
+
|
|
370
|
+
if ambiguous_names[unqualified_name]
|
|
371
|
+
# already known ambiguous, skip
|
|
372
|
+
elsif unqualified_names.key?(unqualified_name)
|
|
373
|
+
unqualified_names.delete(unqualified_name)
|
|
374
|
+
ambiguous_names[unqualified_name] = true
|
|
375
|
+
else
|
|
376
|
+
unqualified_names[unqualified_name] = cm.path
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
lookup.merge!(unqualified_names)
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
##
|
|
384
|
+
# Stores RBS type signatures loaded from sidecar .rbs files, keyed by
|
|
385
|
+
# "ClassName#method" or "ClassName.method". Replaces any previously
|
|
386
|
+
# stored set, so passing +{}+ clears it. Inline +#:+ annotations on
|
|
387
|
+
# method objects are NOT touched — those are owned by the source file.
|
|
388
|
+
|
|
389
|
+
def merge_rbs_signatures(signatures)
|
|
390
|
+
@rbs_signatures = signatures
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
##
|
|
394
|
+
# Returns the RBS type signature lines for +method_attr+ from loaded
|
|
395
|
+
# sidecar +.rbs+ files, or +nil+ if none. Falls through to the
|
|
396
|
+
# canonical method for aliases, and handles +initialize+ -> +.new+
|
|
397
|
+
# singleton mapping.
|
|
398
|
+
|
|
399
|
+
def rbs_signature_for(method_attr)
|
|
400
|
+
return nil unless @rbs_signatures
|
|
401
|
+
cm = method_attr.parent
|
|
402
|
+
return nil unless cm.respond_to?(:full_name)
|
|
403
|
+
|
|
404
|
+
key = method_attr.singleton ? "#{cm.full_name}.#{method_attr.name}" : "#{cm.full_name}##{method_attr.name}"
|
|
405
|
+
sig = @rbs_signatures[key]
|
|
406
|
+
|
|
407
|
+
# RBS keys constructors as #initialize, but RDoc renames them to .new
|
|
408
|
+
if !sig && method_attr.name == 'new' && method_attr.singleton
|
|
409
|
+
sig = @rbs_signatures["#{cm.full_name}#initialize"]
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# For aliases, fall through to the canonical method (its inline #:
|
|
413
|
+
# takes precedence over any sidecar signature on the alias's name).
|
|
414
|
+
if !sig && method_attr.is_alias_for
|
|
415
|
+
canonical = method_attr.is_alias_for
|
|
416
|
+
sig = canonical.type_signature_lines || rbs_signature_for(canonical)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
sig
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def clear_rbs_signatures # :nodoc:
|
|
423
|
+
@rbs_signatures = nil
|
|
424
|
+
end
|
|
425
|
+
|
|
231
426
|
##
|
|
232
427
|
# All TopLevels known to RDoc
|
|
233
428
|
|
|
@@ -978,6 +1173,19 @@ class RDoc::Store
|
|
|
978
1173
|
end
|
|
979
1174
|
|
|
980
1175
|
private
|
|
1176
|
+
|
|
1177
|
+
def remove_classes_and_modules(cms)
|
|
1178
|
+
cms.each do |cm|
|
|
1179
|
+
remove_classes_and_modules(cm.classes_and_modules)
|
|
1180
|
+
|
|
1181
|
+
if cm.is_a?(RDoc::NormalModule)
|
|
1182
|
+
@modules_hash.delete(cm.full_name)
|
|
1183
|
+
else
|
|
1184
|
+
@classes_hash.delete(cm.full_name)
|
|
1185
|
+
end
|
|
1186
|
+
end
|
|
1187
|
+
end
|
|
1188
|
+
|
|
981
1189
|
def marshal_load(file)
|
|
982
1190
|
File.open(file, 'rb') {|io| Marshal.load(io, MarshalFilter)}
|
|
983
1191
|
end
|
data/lib/rdoc/task.rb
CHANGED
|
@@ -202,21 +202,6 @@ class RDoc::Task < Rake::TaskLib
|
|
|
202
202
|
@options = []
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
-
##
|
|
206
|
-
# All source is inline now. This method is deprecated
|
|
207
|
-
|
|
208
|
-
def inline_source # :nodoc:
|
|
209
|
-
warn "RDoc::Task#inline_source is deprecated"
|
|
210
|
-
true
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
##
|
|
214
|
-
# All source is inline now. This method is deprecated
|
|
215
|
-
|
|
216
|
-
def inline_source=(value) # :nodoc:
|
|
217
|
-
warn "RDoc::Task#inline_source is deprecated"
|
|
218
|
-
end
|
|
219
|
-
|
|
220
205
|
##
|
|
221
206
|
# Create the tasks defined by this task lib.
|
|
222
207
|
|
|
@@ -260,6 +245,15 @@ class RDoc::Task < Rake::TaskLib
|
|
|
260
245
|
$stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace
|
|
261
246
|
RDoc::RDoc.new.document args
|
|
262
247
|
end
|
|
248
|
+
|
|
249
|
+
desc server_task_description
|
|
250
|
+
task "server" do
|
|
251
|
+
@before_running_rdoc.call if @before_running_rdoc
|
|
252
|
+
args = option_list + ["--server"] + @rdoc_files
|
|
253
|
+
|
|
254
|
+
$stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace
|
|
255
|
+
RDoc::RDoc.new.document args
|
|
256
|
+
end
|
|
263
257
|
end
|
|
264
258
|
|
|
265
259
|
self
|
|
@@ -309,6 +303,13 @@ class RDoc::Task < Rake::TaskLib
|
|
|
309
303
|
"Print RDoc coverage report"
|
|
310
304
|
end
|
|
311
305
|
|
|
306
|
+
##
|
|
307
|
+
# Task description for the server task
|
|
308
|
+
|
|
309
|
+
def server_task_description
|
|
310
|
+
"Start a live-reloading documentation server"
|
|
311
|
+
end
|
|
312
|
+
|
|
312
313
|
private
|
|
313
314
|
|
|
314
315
|
def rdoc_target
|