rdoc 6.15.1 → 7.1.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 +196 -0
- data/History.rdoc +1 -1
- data/LEGAL.rdoc +6 -0
- data/README.md +90 -7
- data/doc/markup_reference/markdown.md +558 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/lib/rdoc/code_object/any_method.rb +15 -7
- data/lib/rdoc/code_object/class_module.rb +62 -11
- data/lib/rdoc/code_object/constant.rb +9 -0
- data/lib/rdoc/code_object/context/section.rb +20 -1
- data/lib/rdoc/code_object/method_attr.rb +13 -1
- data/lib/rdoc/code_object/top_level.rb +31 -18
- data/lib/rdoc/comment.rb +190 -8
- data/lib/rdoc/cross_reference.rb +30 -21
- data/lib/rdoc/generator/aliki.rb +183 -0
- data/lib/rdoc/generator/darkfish.rb +8 -2
- data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +8 -0
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +23 -0
- data/lib/rdoc/generator/template/aliki/_head.rhtml +158 -0
- data/lib/rdoc/generator/template/aliki/_header.rhtml +56 -0
- data/lib/rdoc/generator/template/aliki/_icons.rhtml +208 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_ancestors.rhtml +16 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_classes.rhtml +15 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +25 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +25 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +16 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_methods.rhtml +41 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +67 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +15 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +21 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +3 -0
- data/lib/rdoc/generator/template/aliki/class.rhtml +220 -0
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +1963 -0
- data/lib/rdoc/generator/template/aliki/index.rhtml +22 -0
- data/lib/rdoc/generator/template/aliki/js/aliki.js +505 -0
- data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +299 -0
- data/lib/rdoc/generator/template/aliki/js/search_controller.js +129 -0
- data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
- data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
- data/lib/rdoc/generator/template/aliki/js/theme-toggle.js +112 -0
- data/lib/rdoc/generator/template/aliki/page.rhtml +18 -0
- data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +14 -0
- data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +65 -0
- data/lib/rdoc/generator/template/darkfish/_head.rhtml +2 -7
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +1 -0
- data/lib/rdoc/generator/template/darkfish/class.rhtml +11 -11
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -0
- data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +1 -1
- data/lib/rdoc/generator/template/json_index/js/searcher.js +5 -1
- data/lib/rdoc/generator.rb +1 -0
- data/lib/rdoc/markdown.kpeg +1 -5
- data/lib/rdoc/markdown.rb +1 -5
- data/lib/rdoc/markup/attribute_manager.rb +28 -1
- data/lib/rdoc/markup/blank_line.rb +25 -23
- data/lib/rdoc/markup/element.rb +21 -0
- data/lib/rdoc/markup/hard_break.rb +30 -27
- data/lib/rdoc/markup/heading.rb +166 -77
- data/lib/rdoc/markup/pre_process.rb +34 -10
- data/lib/rdoc/markup/raw.rb +52 -55
- data/lib/rdoc/markup/table.rb +48 -40
- data/lib/rdoc/markup/to_ansi.rb +4 -0
- data/lib/rdoc/markup/to_bs.rb +4 -0
- data/lib/rdoc/markup/to_html.rb +37 -15
- data/lib/rdoc/markup/to_html_crossref.rb +24 -5
- data/lib/rdoc/markup/to_label.rb +11 -1
- data/lib/rdoc/markup/to_rdoc.rb +11 -3
- data/lib/rdoc/markup/verbatim.rb +1 -1
- data/lib/rdoc/markup.rb +3 -2
- data/lib/rdoc/options.rb +21 -10
- data/lib/rdoc/parser/c.rb +15 -46
- data/lib/rdoc/parser/changelog.rb +8 -0
- data/lib/rdoc/parser/prism_ruby.rb +121 -113
- data/lib/rdoc/parser/ruby.rb +8 -8
- data/lib/rdoc/parser/ruby_tools.rb +5 -7
- data/lib/rdoc/parser/simple.rb +4 -21
- data/lib/rdoc/rdoc.rb +1 -0
- data/lib/rdoc/rubygems_hook.rb +3 -3
- data/lib/rdoc/text.rb +16 -1
- data/lib/rdoc/token_stream.rb +17 -9
- data/lib/rdoc/tom_doc.rb +1 -1
- data/lib/rdoc/version.rb +1 -1
- data/rdoc.gemspec +3 -3
- metadata +36 -9
- data/CONTRIBUTING.rdoc +0 -219
- data/ExampleMarkdown.md +0 -39
- data/ExampleRDoc.rdoc +0 -210
|
@@ -351,7 +351,6 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|
|
351
351
|
return call_seq unless is_alias_for || !aliases.empty?
|
|
352
352
|
|
|
353
353
|
method_name = self.name
|
|
354
|
-
method_name = method_name[0, 1] if method_name =~ /\A\[/
|
|
355
354
|
|
|
356
355
|
entries = call_seq.split "\n"
|
|
357
356
|
|
|
@@ -360,15 +359,24 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|
|
360
359
|
ignore << is_alias_for.name
|
|
361
360
|
ignore.concat is_alias_for.aliases.map(&:name)
|
|
362
361
|
end
|
|
363
|
-
|
|
362
|
+
|
|
364
363
|
ignore.delete(method_name)
|
|
365
|
-
|
|
364
|
+
ignore_bracket_methods, ignore_other_methods = ignore.partition {|i| i.start_with?('[') }
|
|
366
365
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
366
|
+
if ignore_other_methods.any?
|
|
367
|
+
ignore_union = Regexp.union(ignore_other_methods)
|
|
368
|
+
entries.reject! do |entry|
|
|
369
|
+
/\A(?:\w*\.)?#{ignore_union}(?:[(\s]|\z)/.match?(entry) ||
|
|
370
|
+
/\s#{ignore_union}\s/.match?(entry)
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
if ignore_bracket_methods.any?
|
|
374
|
+
entries.reject! do |entry|
|
|
375
|
+
# Ignore `receiver[arg] -> return_type` `[](arg)` `[]`
|
|
376
|
+
/\A\w*\[.*?\](?:[(\s]|\z)/.match?(entry)
|
|
377
|
+
end
|
|
370
378
|
end
|
|
371
379
|
|
|
372
|
-
|
|
380
|
+
entries.empty? ? nil : entries.join("\n")
|
|
373
381
|
end
|
|
374
382
|
end
|
|
@@ -30,7 +30,22 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
30
30
|
attr_accessor :constant_aliases
|
|
31
31
|
|
|
32
32
|
##
|
|
33
|
-
#
|
|
33
|
+
# An array of `[comment, location]` pairs documenting this class/module.
|
|
34
|
+
# Use #add_comment to add comments.
|
|
35
|
+
#
|
|
36
|
+
# Before marshalling:
|
|
37
|
+
# - +comment+ is a String
|
|
38
|
+
# - +location+ is an RDoc::TopLevel
|
|
39
|
+
#
|
|
40
|
+
# After unmarshalling:
|
|
41
|
+
# - +comment+ is an RDoc::Markup::Document
|
|
42
|
+
# - +location+ is a filename String
|
|
43
|
+
#
|
|
44
|
+
# These type changes are acceptable (for now) because:
|
|
45
|
+
# - +comment+: Both String and Document respond to #empty?, and #parse
|
|
46
|
+
# returns Document as-is (see RDoc::Text#parse)
|
|
47
|
+
# - +location+: Only used by #parse to set Document#file, which accepts
|
|
48
|
+
# both TopLevel (extracts relative_name) and String
|
|
34
49
|
|
|
35
50
|
attr_accessor :comment_location
|
|
36
51
|
|
|
@@ -110,7 +125,7 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
110
125
|
@is_alias_for = nil
|
|
111
126
|
@name = name
|
|
112
127
|
@superclass = superclass
|
|
113
|
-
@comment_location = [] # [
|
|
128
|
+
@comment_location = [] # Array of [comment, location] pairs
|
|
114
129
|
|
|
115
130
|
super()
|
|
116
131
|
end
|
|
@@ -173,10 +188,26 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
173
188
|
end
|
|
174
189
|
|
|
175
190
|
##
|
|
176
|
-
# HTML fragment reference for this module or class
|
|
177
|
-
#
|
|
191
|
+
# HTML fragment reference for this module or class using GitHub-style
|
|
192
|
+
# anchor format (lowercase, :: replaced with -).
|
|
193
|
+
#
|
|
194
|
+
# Examples:
|
|
195
|
+
# Foo -> class-foo
|
|
196
|
+
# Foo::Bar -> class-foo-bar
|
|
178
197
|
|
|
179
198
|
def aref
|
|
199
|
+
"#{aref_prefix}-#{full_name.downcase.gsub('::', '-')}"
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
##
|
|
203
|
+
# Legacy HTML fragment reference for backward compatibility.
|
|
204
|
+
# Returns the old RDoc-style anchor format.
|
|
205
|
+
#
|
|
206
|
+
# Examples:
|
|
207
|
+
# Foo -> class-Foo
|
|
208
|
+
# Foo::Bar -> class-Foo::Bar
|
|
209
|
+
|
|
210
|
+
def legacy_aref
|
|
180
211
|
"#{aref_prefix}-#{full_name}"
|
|
181
212
|
end
|
|
182
213
|
|
|
@@ -379,10 +410,10 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
379
410
|
|
|
380
411
|
@comment = RDoc::Comment.from_document document
|
|
381
412
|
|
|
382
|
-
@comment_location = if RDoc::Markup::Document
|
|
383
|
-
document
|
|
413
|
+
@comment_location = if document.parts.first.is_a?(RDoc::Markup::Document)
|
|
414
|
+
document.parts.map { |doc| [doc, doc.file] }
|
|
384
415
|
else
|
|
385
|
-
|
|
416
|
+
[[document, document.file]]
|
|
386
417
|
end
|
|
387
418
|
|
|
388
419
|
array[5].each do |name, rw, visibility, singleton, file|
|
|
@@ -462,7 +493,12 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
462
493
|
document = document.merge other_document
|
|
463
494
|
|
|
464
495
|
@comment = RDoc::Comment.from_document(document)
|
|
465
|
-
|
|
496
|
+
|
|
497
|
+
@comment_location = if document.parts.first.is_a?(RDoc::Markup::Document)
|
|
498
|
+
document.parts.map { |doc| [doc, doc.file] }
|
|
499
|
+
else
|
|
500
|
+
[[document, document.file]]
|
|
501
|
+
end
|
|
466
502
|
end
|
|
467
503
|
|
|
468
504
|
cm = class_module
|
|
@@ -689,6 +725,9 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
689
725
|
|
|
690
726
|
##
|
|
691
727
|
# Search record used by RDoc::Generator::JsonIndex
|
|
728
|
+
#
|
|
729
|
+
# TODO: Remove this method after dropping the darkfish theme and JsonIndex generator.
|
|
730
|
+
# Use #search_snippet instead for getting documentation snippets.
|
|
692
731
|
|
|
693
732
|
def search_record
|
|
694
733
|
[
|
|
@@ -702,6 +741,16 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
702
741
|
]
|
|
703
742
|
end
|
|
704
743
|
|
|
744
|
+
##
|
|
745
|
+
# Returns an HTML snippet of the first comment for search results.
|
|
746
|
+
|
|
747
|
+
def search_snippet
|
|
748
|
+
first_comment = @comment_location.first&.first
|
|
749
|
+
return '' unless first_comment && !first_comment.empty?
|
|
750
|
+
|
|
751
|
+
snippet(first_comment)
|
|
752
|
+
end
|
|
753
|
+
|
|
705
754
|
##
|
|
706
755
|
# Sets the store for this class or module and its contained code objects.
|
|
707
756
|
|
|
@@ -794,11 +843,13 @@ class RDoc::ClassModule < RDoc::Context
|
|
|
794
843
|
cm_alias = cm.dup
|
|
795
844
|
cm_alias.name = const.name
|
|
796
845
|
|
|
797
|
-
|
|
798
|
-
|
|
846
|
+
if full_name == 'Object'
|
|
847
|
+
# Don't move top-level aliases under Object, they look ugly there
|
|
848
|
+
cm_alias.parent = top_level
|
|
849
|
+
else
|
|
799
850
|
cm_alias.parent = self
|
|
800
|
-
cm_alias.full_name = nil # force update for new parent
|
|
801
851
|
end
|
|
852
|
+
cm_alias.full_name = nil # force update for new parent
|
|
802
853
|
|
|
803
854
|
cm_alias.aliases.clear
|
|
804
855
|
cm_alias.is_alias_for = cm
|
|
@@ -154,6 +154,15 @@ class RDoc::Constant < RDoc::CodeObject
|
|
|
154
154
|
"#{@parent.path}##{@name}"
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
+
##
|
|
158
|
+
# Returns an HTML snippet of the comment for search results.
|
|
159
|
+
|
|
160
|
+
def search_snippet
|
|
161
|
+
return '' if comment.empty?
|
|
162
|
+
|
|
163
|
+
snippet(comment)
|
|
164
|
+
end
|
|
165
|
+
|
|
157
166
|
def pretty_print(q) # :nodoc:
|
|
158
167
|
q.group 2, "[#{self.class.name} #{full_name}", "]" do
|
|
159
168
|
unless comment.empty? then
|
|
@@ -70,11 +70,30 @@ class RDoc::Context::Section
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
##
|
|
73
|
-
# Anchor reference for linking to this section
|
|
73
|
+
# Anchor reference for linking to this section using GitHub-style format.
|
|
74
|
+
#
|
|
75
|
+
# Examples:
|
|
76
|
+
# "Section" -> "section"
|
|
77
|
+
# "One Two" -> "one-two"
|
|
78
|
+
# "[untitled]" -> "untitled"
|
|
74
79
|
|
|
75
80
|
def aref
|
|
76
81
|
title = @title || '[untitled]'
|
|
77
82
|
|
|
83
|
+
RDoc::Text.to_anchor(title)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# Legacy anchor reference for backward compatibility.
|
|
88
|
+
#
|
|
89
|
+
# Examples:
|
|
90
|
+
# "Section" -> "section"
|
|
91
|
+
# "One Two" -> "one+two"
|
|
92
|
+
# "[untitled]" -> "5Buntitled-5D"
|
|
93
|
+
|
|
94
|
+
def legacy_aref
|
|
95
|
+
title = @title || '[untitled]'
|
|
96
|
+
|
|
78
97
|
CGI.escape(title).gsub('%', '-').sub(/^-/, '')
|
|
79
98
|
end
|
|
80
99
|
|
|
@@ -375,6 +375,9 @@ class RDoc::MethodAttr < RDoc::CodeObject
|
|
|
375
375
|
##
|
|
376
376
|
# Used by RDoc::Generator::JsonIndex to create a record for the search
|
|
377
377
|
# engine.
|
|
378
|
+
#
|
|
379
|
+
# TODO: Remove this method after dropping the darkfish theme and JsonIndex generator.
|
|
380
|
+
# Use #search_snippet instead for getting documentation snippets.
|
|
378
381
|
|
|
379
382
|
def search_record
|
|
380
383
|
[
|
|
@@ -384,10 +387,19 @@ class RDoc::MethodAttr < RDoc::CodeObject
|
|
|
384
387
|
@parent.full_name,
|
|
385
388
|
path,
|
|
386
389
|
params,
|
|
387
|
-
|
|
390
|
+
search_snippet,
|
|
388
391
|
]
|
|
389
392
|
end
|
|
390
393
|
|
|
394
|
+
##
|
|
395
|
+
# Returns an HTML snippet of the comment for search results.
|
|
396
|
+
|
|
397
|
+
def search_snippet
|
|
398
|
+
return '' if @comment.empty?
|
|
399
|
+
|
|
400
|
+
snippet(@comment)
|
|
401
|
+
end
|
|
402
|
+
|
|
391
403
|
def to_s # :nodoc:
|
|
392
404
|
if @is_alias_for
|
|
393
405
|
"#{self.class.name}: #{full_name} -> #{is_alias_for}"
|
|
@@ -16,6 +16,16 @@ class RDoc::TopLevel < RDoc::Context
|
|
|
16
16
|
|
|
17
17
|
attr_accessor :absolute_name
|
|
18
18
|
|
|
19
|
+
##
|
|
20
|
+
# Base name of this file
|
|
21
|
+
|
|
22
|
+
attr_reader :base_name
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Base name of this file without the extension
|
|
26
|
+
|
|
27
|
+
attr_reader :page_name
|
|
28
|
+
|
|
19
29
|
##
|
|
20
30
|
# All the classes or modules that were declared in
|
|
21
31
|
# this file. These are assigned to either +#classes_hash+
|
|
@@ -40,6 +50,14 @@ class RDoc::TopLevel < RDoc::Context
|
|
|
40
50
|
@relative_name = relative_name
|
|
41
51
|
@parser = nil
|
|
42
52
|
|
|
53
|
+
if relative_name
|
|
54
|
+
@base_name = File.basename(relative_name)
|
|
55
|
+
@page_name = @base_name.sub(/\.(rb|rdoc|txt|md)\z/i, '')
|
|
56
|
+
else
|
|
57
|
+
@base_name = nil
|
|
58
|
+
@page_name = nil
|
|
59
|
+
end
|
|
60
|
+
|
|
43
61
|
@classes_or_modules = []
|
|
44
62
|
end
|
|
45
63
|
|
|
@@ -105,13 +123,6 @@ class RDoc::TopLevel < RDoc::Context
|
|
|
105
123
|
@classes_or_modules << mod
|
|
106
124
|
end
|
|
107
125
|
|
|
108
|
-
##
|
|
109
|
-
# Base name of this file
|
|
110
|
-
|
|
111
|
-
def base_name
|
|
112
|
-
File.basename @relative_name
|
|
113
|
-
end
|
|
114
|
-
|
|
115
126
|
alias name base_name
|
|
116
127
|
|
|
117
128
|
##
|
|
@@ -204,16 +215,6 @@ class RDoc::TopLevel < RDoc::Context
|
|
|
204
215
|
end
|
|
205
216
|
end
|
|
206
217
|
|
|
207
|
-
##
|
|
208
|
-
# Base name of this file without the extension
|
|
209
|
-
|
|
210
|
-
def page_name
|
|
211
|
-
basename = File.basename @relative_name
|
|
212
|
-
basename =~ /\.(rb|rdoc|txt|md)$/i
|
|
213
|
-
|
|
214
|
-
$` || basename
|
|
215
|
-
end
|
|
216
|
-
|
|
217
218
|
##
|
|
218
219
|
# Path to this file for use with HTML generator output.
|
|
219
220
|
|
|
@@ -236,6 +237,9 @@ class RDoc::TopLevel < RDoc::Context
|
|
|
236
237
|
|
|
237
238
|
##
|
|
238
239
|
# Search record used by RDoc::Generator::JsonIndex
|
|
240
|
+
#
|
|
241
|
+
# TODO: Remove this method after dropping the darkfish theme and JsonIndex generator.
|
|
242
|
+
# Use #search_snippet instead for getting documentation snippets.
|
|
239
243
|
|
|
240
244
|
def search_record
|
|
241
245
|
return unless @parser < RDoc::Parser::Text
|
|
@@ -247,10 +251,19 @@ class RDoc::TopLevel < RDoc::Context
|
|
|
247
251
|
'',
|
|
248
252
|
path,
|
|
249
253
|
'',
|
|
250
|
-
|
|
254
|
+
search_snippet,
|
|
251
255
|
]
|
|
252
256
|
end
|
|
253
257
|
|
|
258
|
+
##
|
|
259
|
+
# Returns an HTML snippet of the comment for search results.
|
|
260
|
+
|
|
261
|
+
def search_snippet
|
|
262
|
+
return '' if @comment.empty?
|
|
263
|
+
|
|
264
|
+
snippet(@comment)
|
|
265
|
+
end
|
|
266
|
+
|
|
254
267
|
##
|
|
255
268
|
# Is this TopLevel from a text file instead of a source code file?
|
|
256
269
|
|
data/lib/rdoc/comment.rb
CHANGED
|
@@ -162,6 +162,12 @@ class RDoc::Comment
|
|
|
162
162
|
self
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
+
# Change normalized, when creating already normalized comment.
|
|
166
|
+
|
|
167
|
+
def normalized=(value)
|
|
168
|
+
@normalized = value
|
|
169
|
+
end
|
|
170
|
+
|
|
165
171
|
##
|
|
166
172
|
# Was this text normalized?
|
|
167
173
|
|
|
@@ -223,14 +229,190 @@ class RDoc::Comment
|
|
|
223
229
|
@format == 'tomdoc'
|
|
224
230
|
end
|
|
225
231
|
|
|
226
|
-
|
|
227
|
-
# Create a new parsed comment from a document
|
|
232
|
+
MULTILINE_DIRECTIVES = %w[call-seq].freeze # :nodoc:
|
|
228
233
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
234
|
+
# There are more, but already handled by RDoc::Parser::C
|
|
235
|
+
COLON_LESS_DIRECTIVES = %w[call-seq Document-method].freeze # :nodoc:
|
|
236
|
+
|
|
237
|
+
DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP = /\A(?<colon>\\?:|:?)(?<directive>[\w-]+):(?<param>.*)/
|
|
238
|
+
|
|
239
|
+
private_constant :MULTILINE_DIRECTIVES, :COLON_LESS_DIRECTIVES, :DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP
|
|
240
|
+
|
|
241
|
+
class << self
|
|
242
|
+
|
|
243
|
+
##
|
|
244
|
+
# Create a new parsed comment from a document
|
|
235
245
|
|
|
246
|
+
def from_document(document) # :nodoc:
|
|
247
|
+
comment = RDoc::Comment.new('')
|
|
248
|
+
comment.document = document
|
|
249
|
+
comment.location = RDoc::TopLevel.new(document.file) if document.file
|
|
250
|
+
comment
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Parse comment, collect directives as an attribute and return [normalized_comment_text, directives_hash]
|
|
254
|
+
# This method expands include and removes everything not needed in the document text, such as
|
|
255
|
+
# private section, directive line, comment characters `# /* * */` and indent spaces.
|
|
256
|
+
#
|
|
257
|
+
# RDoc comment consists of include, directive, multiline directive, private section and comment text.
|
|
258
|
+
#
|
|
259
|
+
# Include
|
|
260
|
+
# # :include: filename
|
|
261
|
+
#
|
|
262
|
+
# Directive
|
|
263
|
+
# # :directive-without-value:
|
|
264
|
+
# # :directive-with-value: value
|
|
265
|
+
#
|
|
266
|
+
# Multiline directive (only :call-seq:)
|
|
267
|
+
# # :multiline-directive:
|
|
268
|
+
# # value1
|
|
269
|
+
# # value2
|
|
270
|
+
#
|
|
271
|
+
# Private section
|
|
272
|
+
# #--
|
|
273
|
+
# # private comment
|
|
274
|
+
# #++
|
|
275
|
+
|
|
276
|
+
def parse(text, filename, line_no, type, &include_callback)
|
|
277
|
+
case type
|
|
278
|
+
when :ruby
|
|
279
|
+
text = text.gsub(/^#+/, '') if text.start_with?('#')
|
|
280
|
+
private_start_regexp = /^-{2,}$/
|
|
281
|
+
private_end_regexp = /^\+{2}$/
|
|
282
|
+
indent_regexp = /^\s*/
|
|
283
|
+
when :c
|
|
284
|
+
private_start_regexp = /^(\s*\*)?-{2,}$/
|
|
285
|
+
private_end_regexp = /^(\s*\*)?\+{2}$/
|
|
286
|
+
indent_regexp = /^\s*(\/\*+|\*)?\s*/
|
|
287
|
+
text = text.gsub(/\s*\*+\/\s*\z/, '')
|
|
288
|
+
when :simple
|
|
289
|
+
# Unlike other types, this implementation only looks for two dashes at
|
|
290
|
+
# the beginning of the line. Three or more dashes are considered to be
|
|
291
|
+
# a rule and ignored.
|
|
292
|
+
private_start_regexp = /^-{2}$/
|
|
293
|
+
private_end_regexp = /^\+{2}$/
|
|
294
|
+
indent_regexp = /^\s*/
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
directives = {}
|
|
298
|
+
lines = text.split("\n")
|
|
299
|
+
in_private = false
|
|
300
|
+
comment_lines = []
|
|
301
|
+
until lines.empty?
|
|
302
|
+
line = lines.shift
|
|
303
|
+
read_lines = 1
|
|
304
|
+
if in_private
|
|
305
|
+
# If `++` appears in a private section that starts with `--`, private section ends.
|
|
306
|
+
in_private = false if line.match?(private_end_regexp)
|
|
307
|
+
line_no += read_lines
|
|
308
|
+
next
|
|
309
|
+
elsif line.match?(private_start_regexp)
|
|
310
|
+
# If `--` appears in a line, private section starts.
|
|
311
|
+
in_private = true
|
|
312
|
+
line_no += read_lines
|
|
313
|
+
next
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
prefix = line[indent_regexp]
|
|
317
|
+
prefix_indent = ' ' * prefix.size
|
|
318
|
+
line = line.byteslice(prefix.bytesize..)
|
|
319
|
+
|
|
320
|
+
if (directive_match = DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP.match(line))
|
|
321
|
+
colon = directive_match[:colon]
|
|
322
|
+
directive = directive_match[:directive]
|
|
323
|
+
raw_param = directive_match[:param]
|
|
324
|
+
param = raw_param.strip
|
|
325
|
+
else
|
|
326
|
+
colon = directive = raw_param = param = nil
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
if !directive
|
|
330
|
+
comment_lines << prefix_indent + line
|
|
331
|
+
elsif colon == '\\:'
|
|
332
|
+
# If directive is escaped, unescape it
|
|
333
|
+
comment_lines << prefix_indent + line.sub('\\:', ':')
|
|
334
|
+
elsif raw_param.start_with?(':') || (colon.empty? && !COLON_LESS_DIRECTIVES.include?(directive))
|
|
335
|
+
# Something like `:toto::` is not a directive
|
|
336
|
+
# Only few directives allows to start without a colon
|
|
337
|
+
comment_lines << prefix_indent + line
|
|
338
|
+
elsif directive == 'include'
|
|
339
|
+
filename_to_include = param
|
|
340
|
+
include_callback.call(filename_to_include, prefix_indent).lines.each { |l| comment_lines << l.chomp }
|
|
341
|
+
elsif MULTILINE_DIRECTIVES.include?(directive)
|
|
342
|
+
value_lines = take_multiline_directive_value_lines(directive, filename, line_no, lines, prefix_indent.size, indent_regexp, !param.empty?)
|
|
343
|
+
read_lines += value_lines.size
|
|
344
|
+
lines.shift(value_lines.size)
|
|
345
|
+
unless param.empty?
|
|
346
|
+
# Accept `:call-seq: first-line\n second-line` for now
|
|
347
|
+
value_lines.unshift(param)
|
|
348
|
+
end
|
|
349
|
+
value = value_lines.join("\n")
|
|
350
|
+
directives[directive] = [value.empty? ? nil : value, line_no]
|
|
351
|
+
else
|
|
352
|
+
directives[directive] = [param.empty? ? nil : param, line_no]
|
|
353
|
+
end
|
|
354
|
+
line_no += read_lines
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
normalized_comment = String.new(encoding: text.encoding) << normalize_comment_lines(comment_lines).join("\n")
|
|
358
|
+
[normalized_comment, directives]
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Remove preceding indent spaces and blank lines from the comment lines
|
|
362
|
+
|
|
363
|
+
private def normalize_comment_lines(lines)
|
|
364
|
+
blank_line_regexp = /\A\s*\z/
|
|
365
|
+
lines = lines.dup
|
|
366
|
+
lines.shift while lines.first&.match?(blank_line_regexp)
|
|
367
|
+
lines.pop while lines.last&.match?(blank_line_regexp)
|
|
368
|
+
|
|
369
|
+
min_spaces = lines.map do |l|
|
|
370
|
+
l.match(/\A *(?=\S)/)&.end(0)
|
|
371
|
+
end.compact.min
|
|
372
|
+
if min_spaces && min_spaces > 0
|
|
373
|
+
lines.map { |l| l[min_spaces..] || '' }
|
|
374
|
+
else
|
|
375
|
+
lines
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Take value lines of multiline directive
|
|
380
|
+
|
|
381
|
+
private def take_multiline_directive_value_lines(directive, filename, line_no, lines, base_indent_size, indent_regexp, has_param)
|
|
382
|
+
return [] if lines.empty?
|
|
383
|
+
|
|
384
|
+
first_indent_size = lines.first.match(indent_regexp).end(0)
|
|
385
|
+
|
|
386
|
+
# Blank line or unindented line is not part of multiline-directive value
|
|
387
|
+
return [] if first_indent_size <= base_indent_size
|
|
388
|
+
|
|
389
|
+
if has_param
|
|
390
|
+
# :multiline-directive: line1
|
|
391
|
+
# line2
|
|
392
|
+
# line3
|
|
393
|
+
#
|
|
394
|
+
value_lines = lines.take_while do |l|
|
|
395
|
+
l.rstrip.match(indent_regexp).end(0) > base_indent_size
|
|
396
|
+
end
|
|
397
|
+
min_indent = value_lines.map { |l| l.match(indent_regexp).end(0) }.min
|
|
398
|
+
value_lines.map { |l| l[min_indent..] }
|
|
399
|
+
else
|
|
400
|
+
# Take indented lines accepting blank lines between them
|
|
401
|
+
value_lines = lines.take_while do |l|
|
|
402
|
+
l = l.rstrip
|
|
403
|
+
indent = l[indent_regexp]
|
|
404
|
+
if indent == l || indent.size >= first_indent_size
|
|
405
|
+
true
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
value_lines.map! { |l| (l[first_indent_size..] || '').chomp }
|
|
409
|
+
|
|
410
|
+
if value_lines.size != lines.size && !value_lines.last.empty?
|
|
411
|
+
warn "#{filename}:#{line_no} Multiline directive :#{directive}: should end with a blank line."
|
|
412
|
+
end
|
|
413
|
+
value_lines.pop while value_lines.last&.empty?
|
|
414
|
+
value_lines
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
236
418
|
end
|
data/lib/rdoc/cross_reference.rb
CHANGED
|
@@ -132,47 +132,56 @@ class RDoc::CrossReference
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
##
|
|
135
|
-
# Returns a method reference to +name
|
|
135
|
+
# Returns a method, attribute or constant reference to +name+
|
|
136
|
+
# if it exists in the containing context object. It returns
|
|
137
|
+
# nil otherwise.
|
|
138
|
+
#
|
|
139
|
+
# For example, this method would decompose name = 'A::CONSTANT' into a
|
|
140
|
+
# container object A and a symbol 'CONSTANT', and it would try to find
|
|
141
|
+
# 'CONSTANT' in A.
|
|
136
142
|
|
|
137
|
-
def
|
|
143
|
+
def resolve_local_symbol(name)
|
|
138
144
|
ref = nil
|
|
145
|
+
type = nil
|
|
146
|
+
container = nil
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
case name
|
|
149
|
+
when /#{CLASS_REGEXP_STR}::([A-Z]\w*)\z/o then
|
|
150
|
+
symbol = $2
|
|
151
|
+
container = @context.find_symbol_module($1)
|
|
152
|
+
when /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o then
|
|
141
153
|
type = $2
|
|
142
154
|
if '.' == type # will find either #method or ::method
|
|
143
|
-
|
|
155
|
+
symbol = $3
|
|
144
156
|
else
|
|
145
|
-
|
|
157
|
+
symbol = "#{type}#{$3}"
|
|
146
158
|
end
|
|
147
159
|
container = @context.find_symbol_module($1)
|
|
148
|
-
|
|
160
|
+
when /^([.#]|::)#{METHOD_REGEXP_STR}/o then
|
|
149
161
|
type = $1
|
|
150
162
|
if '.' == type
|
|
151
|
-
|
|
163
|
+
symbol = $2
|
|
152
164
|
else
|
|
153
|
-
|
|
165
|
+
symbol = "#{type}#{$2}"
|
|
154
166
|
end
|
|
155
167
|
container = @context
|
|
156
|
-
else
|
|
157
|
-
type = nil
|
|
158
|
-
container = nil
|
|
159
168
|
end
|
|
160
169
|
|
|
161
170
|
if container then
|
|
162
171
|
unless RDoc::TopLevel === container then
|
|
163
172
|
if '.' == type then
|
|
164
|
-
if 'new' ==
|
|
165
|
-
ref = container.find_local_symbol
|
|
166
|
-
ref = container.find_ancestor_local_symbol
|
|
173
|
+
if 'new' == symbol then # AnyClassName.new will be class method
|
|
174
|
+
ref = container.find_local_symbol symbol
|
|
175
|
+
ref = container.find_ancestor_local_symbol symbol unless ref
|
|
167
176
|
else
|
|
168
|
-
ref = container.find_local_symbol "::#{
|
|
169
|
-
ref = container.find_ancestor_local_symbol "::#{
|
|
170
|
-
ref = container.find_local_symbol "##{
|
|
171
|
-
ref = container.find_ancestor_local_symbol "##{
|
|
177
|
+
ref = container.find_local_symbol "::#{symbol}"
|
|
178
|
+
ref = container.find_ancestor_local_symbol "::#{symbol}" unless ref
|
|
179
|
+
ref = container.find_local_symbol "##{symbol}" unless ref
|
|
180
|
+
ref = container.find_ancestor_local_symbol "##{symbol}" unless ref
|
|
172
181
|
end
|
|
173
182
|
else
|
|
174
|
-
ref = container.find_local_symbol
|
|
175
|
-
ref = container.find_ancestor_local_symbol
|
|
183
|
+
ref = container.find_local_symbol symbol
|
|
184
|
+
ref = container.find_ancestor_local_symbol symbol unless ref
|
|
176
185
|
end
|
|
177
186
|
end
|
|
178
187
|
end
|
|
@@ -197,7 +206,7 @@ class RDoc::CrossReference
|
|
|
197
206
|
@context.find_symbol name
|
|
198
207
|
end
|
|
199
208
|
|
|
200
|
-
ref =
|
|
209
|
+
ref = resolve_local_symbol name unless ref
|
|
201
210
|
|
|
202
211
|
# Try a page name
|
|
203
212
|
ref = @store.page name if not ref and name =~ /^[\w.\/]+$/
|