rdoc 7.2.0 → 8.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 +4 -7
- data/LICENSE.rdoc +4 -0
- data/README.md +43 -2
- data/RI.md +75 -75
- data/doc/markup_reference/markdown.md +104 -3
- data/exe/rdoc +2 -2
- data/lib/rdoc/code_object/alias.rb +70 -74
- data/lib/rdoc/code_object/any_method.rb +305 -298
- data/lib/rdoc/code_object/attr.rb +150 -143
- data/lib/rdoc/code_object/class_module.rb +801 -765
- data/lib/rdoc/code_object/constant.rb +178 -150
- data/lib/rdoc/code_object/context/section.rb +133 -160
- data/lib/rdoc/code_object/context.rb +925 -952
- data/lib/rdoc/code_object/extend.rb +7 -5
- data/lib/rdoc/code_object/include.rb +7 -5
- data/lib/rdoc/code_object/method_attr.rb +325 -324
- data/lib/rdoc/code_object/mixin.rb +97 -95
- data/lib/rdoc/code_object/normal_class.rb +77 -78
- data/lib/rdoc/code_object/normal_module.rb +61 -59
- data/lib/rdoc/code_object/require.rb +23 -39
- data/lib/rdoc/code_object/single_class.rb +21 -19
- data/lib/rdoc/code_object/top_level.rb +212 -213
- data/lib/rdoc/code_object.rb +305 -305
- data/lib/rdoc/comment.rb +274 -337
- data/lib/rdoc/cross_reference.rb +194 -212
- data/lib/rdoc/encoding.rb +105 -103
- data/lib/rdoc/erb_partial.rb +13 -11
- data/lib/rdoc/erbio.rb +29 -27
- data/lib/rdoc/generator/aliki.rb +165 -140
- data/lib/rdoc/generator/darkfish.rb +647 -631
- data/lib/rdoc/generator/json_index.rb +233 -229
- data/lib/rdoc/generator/markup.rb +165 -122
- data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
- data/lib/rdoc/generator/pot/po.rb +52 -51
- data/lib/rdoc/generator/pot/po_entry.rb +138 -132
- data/lib/rdoc/generator/pot.rb +85 -81
- data/lib/rdoc/generator/ri.rb +23 -19
- data/lib/rdoc/generator/template/aliki/DESIGN.md +538 -0
- data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_head.rhtml +11 -11
- data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
- 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_search.rhtml +4 -4
- 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 +538 -283
- data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/js/aliki.js +80 -102
- 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/_footer.rhtml +1 -1
- 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/generator.rb +48 -46
- data/lib/rdoc/i18n/locale.rb +99 -95
- data/lib/rdoc/i18n/text.rb +109 -105
- data/lib/rdoc/i18n.rb +7 -5
- data/lib/rdoc/markdown/byte_runtime.rb +80 -0
- data/lib/rdoc/markdown.kpeg +30 -21
- data/lib/rdoc/markdown.rb +329 -151
- data/lib/rdoc/markup/block_quote.rb +12 -8
- data/lib/rdoc/markup/document.rb +127 -123
- data/lib/rdoc/markup/formatter.rb +215 -221
- data/lib/rdoc/markup/heading.rb +1 -4
- data/lib/rdoc/markup/include.rb +33 -29
- data/lib/rdoc/markup/indented_paragraph.rb +37 -33
- data/lib/rdoc/markup/inline_parser.rb +281 -277
- data/lib/rdoc/markup/list.rb +80 -88
- data/lib/rdoc/markup/list_item.rb +73 -85
- data/lib/rdoc/markup/paragraph.rb +23 -19
- data/lib/rdoc/markup/parser.rb +501 -497
- data/lib/rdoc/markup/pre_process.rb +284 -305
- data/lib/rdoc/markup/raw.rb +2 -2
- data/lib/rdoc/markup/rule.rb +16 -12
- data/lib/rdoc/markup/to_ansi.rb +143 -139
- data/lib/rdoc/markup/to_bs.rb +72 -68
- data/lib/rdoc/markup/to_html.rb +600 -493
- data/lib/rdoc/markup/to_html_crossref.rb +221 -191
- data/lib/rdoc/markup/to_html_snippet.rb +232 -227
- data/lib/rdoc/markup/to_joined_paragraph.rb +40 -41
- data/lib/rdoc/markup/to_label.rb +63 -59
- data/lib/rdoc/markup/to_markdown.rb +212 -208
- data/lib/rdoc/markup/to_rdoc.rb +336 -332
- data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
- data/lib/rdoc/markup/to_test.rb +60 -56
- data/lib/rdoc/markup/to_tt_only.rb +83 -86
- data/lib/rdoc/markup/verbatim.rb +62 -58
- data/lib/rdoc/markup.rb +198 -196
- data/lib/rdoc/options.rb +1063 -1076
- data/lib/rdoc/parser/c.rb +1039 -1036
- data/lib/rdoc/parser/changelog.rb +319 -315
- data/lib/rdoc/parser/markdown.rb +17 -13
- data/lib/rdoc/parser/rbs.rb +279 -0
- data/lib/rdoc/parser/rd.rb +17 -13
- data/lib/rdoc/parser/ruby.rb +1231 -2222
- data/lib/rdoc/parser/ruby_colorizer.rb +303 -0
- data/lib/rdoc/parser/simple.rb +31 -27
- data/lib/rdoc/parser/text.rb +12 -8
- data/lib/rdoc/parser.rb +230 -221
- data/lib/rdoc/rbs_helper.rb +186 -0
- data/lib/rdoc/rd/inline.rb +57 -53
- data/lib/rdoc/rd.rb +90 -88
- data/lib/rdoc/rdoc.rb +547 -366
- data/lib/rdoc/ri/driver.rb +1141 -1130
- data/lib/rdoc/ri/formatter.rb +7 -3
- data/lib/rdoc/ri/paths.rb +140 -136
- data/lib/rdoc/ri/servlet.rb +456 -0
- data/lib/rdoc/ri/store.rb +4 -2
- data/lib/rdoc/ri/task.rb +55 -51
- data/lib/rdoc/ri.rb +14 -11
- data/lib/rdoc/rubygems_hook.rb +194 -192
- data/lib/rdoc/server.rb +462 -0
- data/lib/rdoc/stats/normal.rb +46 -42
- data/lib/rdoc/stats/quiet.rb +39 -35
- data/lib/rdoc/stats/verbose.rb +35 -31
- data/lib/rdoc/stats.rb +363 -338
- data/lib/rdoc/store.rb +919 -725
- data/lib/rdoc/task.rb +260 -255
- data/lib/rdoc/text.rb +130 -245
- data/lib/rdoc/token_stream.rb +101 -115
- data/lib/rdoc/tom_doc.rb +203 -201
- 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 +36 -20
- 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/markdown/literals.kpeg +0 -21
- data/lib/rdoc/markdown/literals.rb +0 -454
- 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/servlet.rb +0 -452
data/lib/rdoc/comment.rb
CHANGED
|
@@ -1,417 +1,354 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# A comment holds the text comment for a RDoc::CodeObject and provides a
|
|
4
|
-
# unified way of cleaning it up and parsing it into an RDoc::Markup::Document.
|
|
5
|
-
#
|
|
6
|
-
# Each comment may have a different markup format set by #format=. By default
|
|
7
|
-
# 'rdoc' is used. The :markup: directive tells RDoc which format to use.
|
|
8
|
-
#
|
|
9
|
-
# See {RDoc Markup Reference}[rdoc-ref:doc/markup_reference/rdoc.rdoc@Directive+for+Specifying+RDoc+Source+Format].
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class RDoc::Comment
|
|
13
|
-
|
|
14
|
-
include RDoc::Text
|
|
15
|
-
|
|
2
|
+
module RDoc
|
|
16
3
|
##
|
|
17
|
-
#
|
|
4
|
+
# A comment holds the text comment for a RDoc::CodeObject and provides a
|
|
5
|
+
# unified way of cleaning it up and parsing it into an RDoc::Markup::Document.
|
|
6
|
+
#
|
|
7
|
+
# Each comment may have a different markup format set by #format=. By default
|
|
8
|
+
# 'rdoc' is used. The :markup: directive tells RDoc which format to use.
|
|
9
|
+
#
|
|
10
|
+
# See {RDoc Markup Reference}[rdoc-ref:doc/markup_reference/rdoc.rdoc@Directive+for+Specifying+RDoc+Source+Format].
|
|
18
11
|
|
|
19
|
-
attr_reader :format
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
# The RDoc::TopLevel this comment was found in
|
|
13
|
+
class Comment
|
|
23
14
|
|
|
24
|
-
|
|
15
|
+
include Text
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
##
|
|
18
|
+
# The format of this comment. Defaults to RDoc::Markup
|
|
28
19
|
|
|
29
|
-
|
|
20
|
+
attr_reader :format
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
##
|
|
23
|
+
# The RDoc::TopLevel this comment was found in
|
|
33
24
|
|
|
34
|
-
|
|
25
|
+
attr_accessor :location
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
##
|
|
28
|
+
# Line where this Comment was written
|
|
38
29
|
|
|
39
|
-
|
|
30
|
+
attr_accessor :line
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
##
|
|
33
|
+
# For duck-typing when merging classes at load time
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
alias file location # :nodoc:
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# source for this comment
|
|
37
|
+
##
|
|
38
|
+
# The text for this comment
|
|
49
39
|
|
|
50
|
-
|
|
40
|
+
attr_reader :text
|
|
51
41
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# +location+.
|
|
42
|
+
##
|
|
43
|
+
# Alias for text
|
|
55
44
|
|
|
56
|
-
|
|
57
|
-
@location = location
|
|
58
|
-
@text = text.nil? ? nil : text.dup
|
|
59
|
-
@language = language
|
|
45
|
+
alias to_s text
|
|
60
46
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
47
|
+
##
|
|
48
|
+
# Overrides the content returned by #parse. Use when there is no #text
|
|
49
|
+
# source for this comment
|
|
65
50
|
|
|
66
|
-
|
|
67
|
-
#--
|
|
68
|
-
# TODO deep copy @document
|
|
51
|
+
attr_writer :document
|
|
69
52
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
53
|
+
##
|
|
54
|
+
# Creates a new comment with +text+ that is found in the RDoc::TopLevel
|
|
55
|
+
# +location+.
|
|
73
56
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
57
|
+
def initialize(text = nil, location = nil, language = nil)
|
|
58
|
+
@location = location
|
|
59
|
+
@text = text.nil? ? nil : text.dup
|
|
60
|
+
@language = language
|
|
78
61
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# same indentation level and prefix are consumed.
|
|
83
|
-
#
|
|
84
|
-
# For example, all of the following will be used as the :call-seq:
|
|
85
|
-
#
|
|
86
|
-
# # :call-seq:
|
|
87
|
-
# # ARGF.readlines(sep=$/) -> array
|
|
88
|
-
# # ARGF.readlines(limit) -> array
|
|
89
|
-
# # ARGF.readlines(sep, limit) -> array
|
|
90
|
-
# #
|
|
91
|
-
# # ARGF.to_a(sep=$/) -> array
|
|
92
|
-
# # ARGF.to_a(limit) -> array
|
|
93
|
-
# # ARGF.to_a(sep, limit) -> array
|
|
94
|
-
|
|
95
|
-
def extract_call_seq
|
|
96
|
-
# we must handle situations like the above followed by an unindented first
|
|
97
|
-
# comment. The difficulty is to make sure not to match lines starting
|
|
98
|
-
# with ARGF at the same indent, but that are after the first description
|
|
99
|
-
# paragraph.
|
|
100
|
-
if /^(?<S> ((?!\n)\s)*+ (?# whitespaces except newline))
|
|
101
|
-
:?call-seq:
|
|
102
|
-
(?<B> \g<S>(?<N>\n|\z) (?# trailing spaces))?
|
|
103
|
-
(?<seq>
|
|
104
|
-
(\g<S>(?!\w)\S.*\g<N>)*
|
|
105
|
-
(?>
|
|
106
|
-
(?<H> \g<S>\w+ (?# ' # ARGF' in the example above))
|
|
107
|
-
.*\g<N>)?
|
|
108
|
-
(\g<S>\S.*\g<N> (?# other non-blank line))*+
|
|
109
|
-
(\g<B>+(\k<H>.*\g<N> (?# ARGF.to_a lines))++)*+
|
|
110
|
-
)
|
|
111
|
-
(?m:^\s*$|\z)
|
|
112
|
-
/x =~ @text
|
|
113
|
-
seq = $~[:seq]
|
|
114
|
-
|
|
115
|
-
all_start, all_stop = $~.offset(0)
|
|
116
|
-
@text.slice! all_start...all_stop
|
|
117
|
-
|
|
118
|
-
seq.gsub!(/^\s*/, '')
|
|
62
|
+
@document = nil
|
|
63
|
+
@format = 'rdoc'
|
|
64
|
+
@normalized = false
|
|
119
65
|
end
|
|
120
|
-
end
|
|
121
66
|
|
|
122
|
-
|
|
123
|
-
|
|
67
|
+
##
|
|
68
|
+
#--
|
|
69
|
+
# TODO deep copy @document
|
|
124
70
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
71
|
+
def initialize_copy(copy) # :nodoc:
|
|
72
|
+
@text = copy.text.dup
|
|
73
|
+
end
|
|
128
74
|
|
|
129
|
-
|
|
130
|
-
|
|
75
|
+
def ==(other) # :nodoc:
|
|
76
|
+
self.class === other and
|
|
77
|
+
other.text == @text and other.location == @location
|
|
78
|
+
end
|
|
131
79
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
self
|
|
135
|
-
end
|
|
80
|
+
##
|
|
81
|
+
# A comment is empty if its text String is empty.
|
|
136
82
|
|
|
137
|
-
|
|
138
|
-
|
|
83
|
+
def empty?
|
|
84
|
+
@text.empty? && (@document.nil? || @document.empty?)
|
|
85
|
+
end
|
|
139
86
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
@document = nil
|
|
143
|
-
end
|
|
87
|
+
##
|
|
88
|
+
# HACK dubious
|
|
144
89
|
|
|
145
|
-
|
|
146
|
-
|
|
90
|
+
def encode!(encoding)
|
|
91
|
+
@text = String.new @text, encoding: encoding
|
|
92
|
+
self
|
|
93
|
+
end
|
|
147
94
|
|
|
148
|
-
|
|
149
|
-
|
|
95
|
+
##
|
|
96
|
+
# Sets the format of this comment and resets any parsed document
|
|
150
97
|
|
|
151
|
-
|
|
152
|
-
|
|
98
|
+
def format=(format)
|
|
99
|
+
@format = format
|
|
100
|
+
@document = nil
|
|
101
|
+
end
|
|
153
102
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return self if @normalized # TODO eliminate duplicate normalization
|
|
103
|
+
def inspect # :nodoc:
|
|
104
|
+
location = @location ? @location.relative_name : '(unknown)'
|
|
157
105
|
|
|
158
|
-
|
|
106
|
+
"#<%s:%x %s %p>" % [self.class, object_id, location, @text]
|
|
107
|
+
end
|
|
159
108
|
|
|
160
|
-
|
|
109
|
+
##
|
|
110
|
+
# Normalizes the text. See RDoc::Text#normalize_comment for details
|
|
161
111
|
|
|
162
|
-
|
|
163
|
-
|
|
112
|
+
def normalize
|
|
113
|
+
return self unless @text
|
|
114
|
+
return self if @normalized # TODO eliminate duplicate normalization
|
|
164
115
|
|
|
165
|
-
|
|
116
|
+
@text = normalize_comment @text
|
|
166
117
|
|
|
167
|
-
|
|
168
|
-
@normalized = value
|
|
169
|
-
end
|
|
118
|
+
@normalized = true
|
|
170
119
|
|
|
171
|
-
|
|
172
|
-
|
|
120
|
+
self
|
|
121
|
+
end
|
|
173
122
|
|
|
174
|
-
|
|
175
|
-
@normalized
|
|
176
|
-
end
|
|
123
|
+
# Change normalized, when creating already normalized comment.
|
|
177
124
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
125
|
+
def normalized=(value)
|
|
126
|
+
@normalized = value
|
|
127
|
+
end
|
|
181
128
|
|
|
182
|
-
|
|
183
|
-
|
|
129
|
+
##
|
|
130
|
+
# Was this text normalized?
|
|
184
131
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
end
|
|
132
|
+
def normalized? # :nodoc:
|
|
133
|
+
@normalized
|
|
134
|
+
end
|
|
189
135
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
# For C-style comments, a private marker may not start at the opening of the
|
|
194
|
-
# comment.
|
|
195
|
-
#
|
|
196
|
-
# /*
|
|
197
|
-
# *--
|
|
198
|
-
# * private
|
|
199
|
-
# *++
|
|
200
|
-
# * public
|
|
201
|
-
# */
|
|
202
|
-
|
|
203
|
-
def remove_private
|
|
204
|
-
# Workaround for gsub encoding for Ruby 1.9.2 and earlier
|
|
205
|
-
empty = ''
|
|
206
|
-
empty = RDoc::Encoding.change_encoding empty, @text.encoding
|
|
207
|
-
|
|
208
|
-
@text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\+\+\n?%m, empty)
|
|
209
|
-
@text = @text.sub(%r%^\s*[#*]?--.*%m, '')
|
|
210
|
-
end
|
|
136
|
+
##
|
|
137
|
+
# Parses the comment into an RDoc::Markup::Document. The parsed document is
|
|
138
|
+
# cached until the text is changed.
|
|
211
139
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#
|
|
215
|
-
# An error is raised if the comment contains a document but no text.
|
|
140
|
+
def parse
|
|
141
|
+
return @document if @document
|
|
216
142
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
@
|
|
143
|
+
@document = super @text, @format
|
|
144
|
+
@document.file = @location
|
|
145
|
+
@document
|
|
146
|
+
end
|
|
220
147
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
148
|
+
##
|
|
149
|
+
# Replaces this comment's text with +text+ and resets the parsed document.
|
|
150
|
+
#
|
|
151
|
+
# An error is raised if the comment contains a document but no text.
|
|
224
152
|
|
|
225
|
-
|
|
226
|
-
|
|
153
|
+
def text=(text)
|
|
154
|
+
raise Error, 'replacing document-only comment is not allowed' if
|
|
155
|
+
@text.nil? and @document
|
|
227
156
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
157
|
+
@document = nil
|
|
158
|
+
@text = text.nil? ? nil : text.dup
|
|
159
|
+
end
|
|
231
160
|
|
|
232
|
-
|
|
161
|
+
##
|
|
162
|
+
# Returns true if this comment is in TomDoc format.
|
|
233
163
|
|
|
234
|
-
|
|
235
|
-
|
|
164
|
+
def tomdoc?
|
|
165
|
+
@format == 'tomdoc'
|
|
166
|
+
end
|
|
236
167
|
|
|
237
|
-
|
|
168
|
+
MULTILINE_DIRECTIVES = %w[call-seq].freeze # :nodoc:
|
|
238
169
|
|
|
239
|
-
|
|
170
|
+
# There are more, but already handled by RDoc::Parser::C
|
|
171
|
+
COLON_LESS_DIRECTIVES = %w[call-seq Document-method].freeze # :nodoc:
|
|
240
172
|
|
|
241
|
-
|
|
173
|
+
DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP = /\A(?<colon>\\?:|:?)(?<directive>[\w-]+):(?<param>.*)/
|
|
242
174
|
|
|
243
|
-
|
|
244
|
-
# Create a new parsed comment from a document
|
|
175
|
+
private_constant :MULTILINE_DIRECTIVES, :COLON_LESS_DIRECTIVES, :DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP
|
|
245
176
|
|
|
246
|
-
|
|
247
|
-
comment = RDoc::Comment.new('')
|
|
248
|
-
comment.document = document
|
|
249
|
-
comment.location = RDoc::TopLevel.new(document.file) if document.file
|
|
250
|
-
comment
|
|
251
|
-
end
|
|
177
|
+
class << self
|
|
252
178
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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*/
|
|
179
|
+
##
|
|
180
|
+
# Create a new parsed comment from a document
|
|
181
|
+
|
|
182
|
+
def from_document(document) # :nodoc:
|
|
183
|
+
comment = Comment.new('')
|
|
184
|
+
comment.document = document
|
|
185
|
+
comment.location = TopLevel.new(document.file) if document.file
|
|
186
|
+
comment
|
|
295
187
|
end
|
|
296
188
|
|
|
297
|
-
directives
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
189
|
+
# Parse comment, collect directives as an attribute and return [normalized_comment_text, directives_hash]
|
|
190
|
+
# This method expands include and removes everything not needed in the document text, such as
|
|
191
|
+
# private section, directive line, comment characters `# /* * */` and indent spaces.
|
|
192
|
+
#
|
|
193
|
+
# RDoc comment consists of include, directive, multiline directive, private section and comment text.
|
|
194
|
+
#
|
|
195
|
+
# Include
|
|
196
|
+
# # :include: filename
|
|
197
|
+
#
|
|
198
|
+
# Directive
|
|
199
|
+
# # :directive-without-value:
|
|
200
|
+
# # :directive-with-value: value
|
|
201
|
+
#
|
|
202
|
+
# Multiline directive (only :call-seq:)
|
|
203
|
+
# # :multiline-directive:
|
|
204
|
+
# # value1
|
|
205
|
+
# # value2
|
|
206
|
+
#
|
|
207
|
+
# Private section
|
|
208
|
+
# #--
|
|
209
|
+
# # private comment
|
|
210
|
+
# #++
|
|
211
|
+
|
|
212
|
+
def parse(text, filename, line_no, type, &include_callback)
|
|
213
|
+
case type
|
|
214
|
+
when :ruby
|
|
215
|
+
text = text.gsub(/^#+/, '') if text.start_with?('#')
|
|
216
|
+
private_start_regexp = /^-{2,}$/
|
|
217
|
+
private_end_regexp = /^\+{2}$/
|
|
218
|
+
indent_regexp = /^\s*/
|
|
219
|
+
when :c
|
|
220
|
+
private_start_regexp = /^(\s*\*)?-{2,}$/
|
|
221
|
+
private_end_regexp = /^(\s*\*)?\+{2}$/
|
|
222
|
+
indent_regexp = /^\s*(\/\*+|\*)?\s*/
|
|
223
|
+
text = text.gsub(/\s*\*+\/\s*\z/, '')
|
|
224
|
+
when :simple
|
|
225
|
+
# Unlike other types, this implementation only looks for two dashes at
|
|
226
|
+
# the beginning of the line. Three or more dashes are considered to be
|
|
227
|
+
# a rule and ignored.
|
|
228
|
+
private_start_regexp = /^-{2}$/
|
|
229
|
+
private_end_regexp = /^\+{2}$/
|
|
230
|
+
indent_regexp = /^\s*/
|
|
314
231
|
end
|
|
315
232
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
233
|
+
directives = {}
|
|
234
|
+
lines = text.split("\n")
|
|
235
|
+
in_private = false
|
|
236
|
+
comment_lines = []
|
|
237
|
+
until lines.empty?
|
|
238
|
+
line = lines.shift
|
|
239
|
+
read_lines = 1
|
|
240
|
+
if in_private
|
|
241
|
+
# If `++` appears in a private section that starts with `--`, private section ends.
|
|
242
|
+
in_private = false if line.match?(private_end_regexp)
|
|
243
|
+
line_no += read_lines
|
|
244
|
+
next
|
|
245
|
+
elsif line.match?(private_start_regexp)
|
|
246
|
+
# If `--` appears in a line, private section starts.
|
|
247
|
+
in_private = true
|
|
248
|
+
line_no += read_lines
|
|
249
|
+
next
|
|
250
|
+
end
|
|
319
251
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
252
|
+
prefix = line[indent_regexp]
|
|
253
|
+
prefix_indent = ' ' * prefix.size
|
|
254
|
+
line = line.byteslice(prefix.bytesize..)
|
|
255
|
+
|
|
256
|
+
if (directive_match = DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP.match(line))
|
|
257
|
+
colon = directive_match[:colon]
|
|
258
|
+
directive = directive_match[:directive]
|
|
259
|
+
raw_param = directive_match[:param]
|
|
260
|
+
param = raw_param.strip
|
|
261
|
+
else
|
|
262
|
+
colon = directive = raw_param = param = nil
|
|
263
|
+
end
|
|
328
264
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
265
|
+
if !directive
|
|
266
|
+
comment_lines << prefix_indent + line
|
|
267
|
+
elsif colon == '\\:'
|
|
268
|
+
# If directive is escaped, unescape it
|
|
269
|
+
comment_lines << prefix_indent + line.sub('\\:', ':')
|
|
270
|
+
elsif raw_param.start_with?(':') || (colon.empty? && !COLON_LESS_DIRECTIVES.include?(directive))
|
|
271
|
+
# Something like `:toto::` is not a directive
|
|
272
|
+
# Only few directives allows to start without a colon
|
|
273
|
+
comment_lines << prefix_indent + line
|
|
274
|
+
elsif directive == 'include'
|
|
275
|
+
filename_to_include = param
|
|
276
|
+
include_callback.call(filename_to_include, prefix_indent).lines.each { |l| comment_lines << l.chomp }
|
|
277
|
+
elsif MULTILINE_DIRECTIVES.include?(directive)
|
|
278
|
+
value_lines = take_multiline_directive_value_lines(directive, filename, line_no, lines, prefix_indent.size, indent_regexp, !param.empty?)
|
|
279
|
+
read_lines += value_lines.size
|
|
280
|
+
lines.shift(value_lines.size)
|
|
281
|
+
unless param.empty?
|
|
282
|
+
# Accept `:call-seq: first-line\n second-line` for now
|
|
283
|
+
value_lines.unshift(param)
|
|
284
|
+
end
|
|
285
|
+
value = value_lines.join("\n")
|
|
286
|
+
directives[directive] = [value.empty? ? nil : value, line_no]
|
|
287
|
+
else
|
|
288
|
+
directives[directive] = [param.empty? ? nil : param, line_no]
|
|
348
289
|
end
|
|
349
|
-
|
|
350
|
-
directives[directive] = [value.empty? ? nil : value, line_no]
|
|
351
|
-
else
|
|
352
|
-
directives[directive] = [param.empty? ? nil : param, line_no]
|
|
290
|
+
line_no += read_lines
|
|
353
291
|
end
|
|
354
|
-
|
|
292
|
+
|
|
293
|
+
normalized_comment = String.new(encoding: text.encoding) << normalize_comment_lines(comment_lines).join("\n")
|
|
294
|
+
[normalized_comment, directives]
|
|
355
295
|
end
|
|
356
296
|
|
|
357
|
-
|
|
358
|
-
[normalized_comment, directives]
|
|
359
|
-
end
|
|
297
|
+
# Remove preceding indent spaces and blank lines from the comment lines
|
|
360
298
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
lines
|
|
299
|
+
private def normalize_comment_lines(lines)
|
|
300
|
+
blank_line_regexp = /\A\s*\z/
|
|
301
|
+
lines = lines.dup
|
|
302
|
+
lines.shift while lines.first&.match?(blank_line_regexp)
|
|
303
|
+
lines.pop while lines.last&.match?(blank_line_regexp)
|
|
304
|
+
|
|
305
|
+
min_spaces = lines.map do |l|
|
|
306
|
+
l.match(/\A *(?=\S)/)&.end(0)
|
|
307
|
+
end.compact.min
|
|
308
|
+
if min_spaces && min_spaces > 0
|
|
309
|
+
lines.map { |l| l[min_spaces..] || '' }
|
|
310
|
+
else
|
|
311
|
+
lines
|
|
312
|
+
end
|
|
376
313
|
end
|
|
377
|
-
end
|
|
378
314
|
|
|
379
|
-
|
|
315
|
+
# Take value lines of multiline directive
|
|
380
316
|
|
|
381
|
-
|
|
382
|
-
|
|
317
|
+
private def take_multiline_directive_value_lines(directive, filename, line_no, lines, base_indent_size, indent_regexp, has_param)
|
|
318
|
+
return [] if lines.empty?
|
|
383
319
|
|
|
384
|
-
|
|
320
|
+
first_indent_size = lines.first.match(indent_regexp).end(0)
|
|
385
321
|
|
|
386
|
-
|
|
387
|
-
|
|
322
|
+
# Blank line or unindented line is not part of multiline-directive value
|
|
323
|
+
return [] if first_indent_size <= base_indent_size
|
|
388
324
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
|
325
|
+
if has_param
|
|
326
|
+
# :multiline-directive: line1
|
|
327
|
+
# line2
|
|
328
|
+
# line3
|
|
329
|
+
#
|
|
330
|
+
value_lines = lines.take_while do |l|
|
|
331
|
+
l.rstrip.match(indent_regexp).end(0) > base_indent_size
|
|
406
332
|
end
|
|
407
|
-
|
|
408
|
-
|
|
333
|
+
min_indent = value_lines.map { |l| l.match(indent_regexp).end(0) }.min
|
|
334
|
+
value_lines.map { |l| l[min_indent..] }
|
|
335
|
+
else
|
|
336
|
+
# Take indented lines accepting blank lines between them
|
|
337
|
+
value_lines = lines.take_while do |l|
|
|
338
|
+
l = l.rstrip
|
|
339
|
+
indent = l[indent_regexp]
|
|
340
|
+
if indent == l || indent.size >= first_indent_size
|
|
341
|
+
true
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
value_lines.map! { |l| (l[first_indent_size..] || '').chomp }
|
|
409
345
|
|
|
410
|
-
|
|
411
|
-
|
|
346
|
+
if value_lines.size != lines.size && !value_lines.last.empty?
|
|
347
|
+
warn "#{filename}:#{line_no} Multiline directive :#{directive}: should end with a blank line."
|
|
348
|
+
end
|
|
349
|
+
value_lines.pop while value_lines.last&.empty?
|
|
350
|
+
value_lines
|
|
412
351
|
end
|
|
413
|
-
value_lines.pop while value_lines.last&.empty?
|
|
414
|
-
value_lines
|
|
415
352
|
end
|
|
416
353
|
end
|
|
417
354
|
end
|