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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +4 -7
  3. data/LICENSE.rdoc +4 -0
  4. data/README.md +43 -2
  5. data/RI.md +75 -75
  6. data/doc/markup_reference/markdown.md +104 -3
  7. data/exe/rdoc +2 -2
  8. data/lib/rdoc/code_object/alias.rb +70 -74
  9. data/lib/rdoc/code_object/any_method.rb +305 -298
  10. data/lib/rdoc/code_object/attr.rb +150 -143
  11. data/lib/rdoc/code_object/class_module.rb +801 -765
  12. data/lib/rdoc/code_object/constant.rb +178 -150
  13. data/lib/rdoc/code_object/context/section.rb +133 -160
  14. data/lib/rdoc/code_object/context.rb +925 -952
  15. data/lib/rdoc/code_object/extend.rb +7 -5
  16. data/lib/rdoc/code_object/include.rb +7 -5
  17. data/lib/rdoc/code_object/method_attr.rb +325 -324
  18. data/lib/rdoc/code_object/mixin.rb +97 -95
  19. data/lib/rdoc/code_object/normal_class.rb +77 -78
  20. data/lib/rdoc/code_object/normal_module.rb +61 -59
  21. data/lib/rdoc/code_object/require.rb +23 -39
  22. data/lib/rdoc/code_object/single_class.rb +21 -19
  23. data/lib/rdoc/code_object/top_level.rb +212 -213
  24. data/lib/rdoc/code_object.rb +305 -305
  25. data/lib/rdoc/comment.rb +274 -337
  26. data/lib/rdoc/cross_reference.rb +194 -212
  27. data/lib/rdoc/encoding.rb +105 -103
  28. data/lib/rdoc/erb_partial.rb +13 -11
  29. data/lib/rdoc/erbio.rb +29 -27
  30. data/lib/rdoc/generator/aliki.rb +165 -140
  31. data/lib/rdoc/generator/darkfish.rb +647 -631
  32. data/lib/rdoc/generator/json_index.rb +233 -229
  33. data/lib/rdoc/generator/markup.rb +165 -122
  34. data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
  35. data/lib/rdoc/generator/pot/po.rb +52 -51
  36. data/lib/rdoc/generator/pot/po_entry.rb +138 -132
  37. data/lib/rdoc/generator/pot.rb +85 -81
  38. data/lib/rdoc/generator/ri.rb +23 -19
  39. data/lib/rdoc/generator/template/aliki/DESIGN.md +538 -0
  40. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  41. data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
  42. data/lib/rdoc/generator/template/aliki/_head.rhtml +11 -11
  43. data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
  44. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  45. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  46. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  47. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
  48. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +4 -4
  49. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  50. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  51. data/lib/rdoc/generator/template/aliki/class.rhtml +56 -46
  52. data/lib/rdoc/generator/template/aliki/css/rdoc.css +538 -283
  53. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  54. data/lib/rdoc/generator/template/aliki/js/aliki.js +80 -102
  55. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  56. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  57. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  58. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +1 -1
  59. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  60. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  61. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  62. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  63. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  64. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  65. data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
  66. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
  67. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  68. data/lib/rdoc/generator.rb +48 -46
  69. data/lib/rdoc/i18n/locale.rb +99 -95
  70. data/lib/rdoc/i18n/text.rb +109 -105
  71. data/lib/rdoc/i18n.rb +7 -5
  72. data/lib/rdoc/markdown/byte_runtime.rb +80 -0
  73. data/lib/rdoc/markdown.kpeg +30 -21
  74. data/lib/rdoc/markdown.rb +329 -151
  75. data/lib/rdoc/markup/block_quote.rb +12 -8
  76. data/lib/rdoc/markup/document.rb +127 -123
  77. data/lib/rdoc/markup/formatter.rb +215 -221
  78. data/lib/rdoc/markup/heading.rb +1 -4
  79. data/lib/rdoc/markup/include.rb +33 -29
  80. data/lib/rdoc/markup/indented_paragraph.rb +37 -33
  81. data/lib/rdoc/markup/inline_parser.rb +281 -277
  82. data/lib/rdoc/markup/list.rb +80 -88
  83. data/lib/rdoc/markup/list_item.rb +73 -85
  84. data/lib/rdoc/markup/paragraph.rb +23 -19
  85. data/lib/rdoc/markup/parser.rb +501 -497
  86. data/lib/rdoc/markup/pre_process.rb +284 -305
  87. data/lib/rdoc/markup/raw.rb +2 -2
  88. data/lib/rdoc/markup/rule.rb +16 -12
  89. data/lib/rdoc/markup/to_ansi.rb +143 -139
  90. data/lib/rdoc/markup/to_bs.rb +72 -68
  91. data/lib/rdoc/markup/to_html.rb +600 -493
  92. data/lib/rdoc/markup/to_html_crossref.rb +221 -191
  93. data/lib/rdoc/markup/to_html_snippet.rb +232 -227
  94. data/lib/rdoc/markup/to_joined_paragraph.rb +40 -41
  95. data/lib/rdoc/markup/to_label.rb +63 -59
  96. data/lib/rdoc/markup/to_markdown.rb +212 -208
  97. data/lib/rdoc/markup/to_rdoc.rb +336 -332
  98. data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
  99. data/lib/rdoc/markup/to_test.rb +60 -56
  100. data/lib/rdoc/markup/to_tt_only.rb +83 -86
  101. data/lib/rdoc/markup/verbatim.rb +62 -58
  102. data/lib/rdoc/markup.rb +198 -196
  103. data/lib/rdoc/options.rb +1063 -1076
  104. data/lib/rdoc/parser/c.rb +1039 -1036
  105. data/lib/rdoc/parser/changelog.rb +319 -315
  106. data/lib/rdoc/parser/markdown.rb +17 -13
  107. data/lib/rdoc/parser/rbs.rb +279 -0
  108. data/lib/rdoc/parser/rd.rb +17 -13
  109. data/lib/rdoc/parser/ruby.rb +1231 -2222
  110. data/lib/rdoc/parser/ruby_colorizer.rb +303 -0
  111. data/lib/rdoc/parser/simple.rb +31 -27
  112. data/lib/rdoc/parser/text.rb +12 -8
  113. data/lib/rdoc/parser.rb +230 -221
  114. data/lib/rdoc/rbs_helper.rb +186 -0
  115. data/lib/rdoc/rd/inline.rb +57 -53
  116. data/lib/rdoc/rd.rb +90 -88
  117. data/lib/rdoc/rdoc.rb +547 -366
  118. data/lib/rdoc/ri/driver.rb +1141 -1130
  119. data/lib/rdoc/ri/formatter.rb +7 -3
  120. data/lib/rdoc/ri/paths.rb +140 -136
  121. data/lib/rdoc/ri/servlet.rb +456 -0
  122. data/lib/rdoc/ri/store.rb +4 -2
  123. data/lib/rdoc/ri/task.rb +55 -51
  124. data/lib/rdoc/ri.rb +14 -11
  125. data/lib/rdoc/rubygems_hook.rb +194 -192
  126. data/lib/rdoc/server.rb +462 -0
  127. data/lib/rdoc/stats/normal.rb +46 -42
  128. data/lib/rdoc/stats/quiet.rb +39 -35
  129. data/lib/rdoc/stats/verbose.rb +35 -31
  130. data/lib/rdoc/stats.rb +363 -338
  131. data/lib/rdoc/store.rb +919 -725
  132. data/lib/rdoc/task.rb +260 -255
  133. data/lib/rdoc/text.rb +130 -245
  134. data/lib/rdoc/token_stream.rb +101 -115
  135. data/lib/rdoc/tom_doc.rb +203 -201
  136. data/lib/rdoc/version.rb +1 -1
  137. data/lib/rdoc.rb +35 -7
  138. data/lib/rubygems_plugin.rb +2 -11
  139. data/rdoc-logo.svg +43 -0
  140. data/rdoc.gemspec +6 -4
  141. metadata +36 -20
  142. data/lib/rdoc/code_object/anon_class.rb +0 -10
  143. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  144. data/lib/rdoc/code_object/meta_method.rb +0 -6
  145. data/lib/rdoc/markdown/literals.kpeg +0 -21
  146. data/lib/rdoc/markdown/literals.rb +0 -454
  147. data/lib/rdoc/parser/prism_ruby.rb +0 -1112
  148. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  149. data/lib/rdoc/parser/ruby_tools.rb +0 -163
  150. 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
- # The format of this comment. Defaults to RDoc::Markup
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
- attr_accessor :location
15
+ include Text
25
16
 
26
- ##
27
- # Line where this Comment was written
17
+ ##
18
+ # The format of this comment. Defaults to RDoc::Markup
28
19
 
29
- attr_accessor :line
20
+ attr_reader :format
30
21
 
31
- ##
32
- # For duck-typing when merging classes at load time
22
+ ##
23
+ # The RDoc::TopLevel this comment was found in
33
24
 
34
- alias file location # :nodoc:
25
+ attr_accessor :location
35
26
 
36
- ##
37
- # The text for this comment
27
+ ##
28
+ # Line where this Comment was written
38
29
 
39
- attr_reader :text
30
+ attr_accessor :line
40
31
 
41
- ##
42
- # Alias for text
32
+ ##
33
+ # For duck-typing when merging classes at load time
43
34
 
44
- alias to_s text
35
+ alias file location # :nodoc:
45
36
 
46
- ##
47
- # Overrides the content returned by #parse. Use when there is no #text
48
- # source for this comment
37
+ ##
38
+ # The text for this comment
49
39
 
50
- attr_writer :document
40
+ attr_reader :text
51
41
 
52
- ##
53
- # Creates a new comment with +text+ that is found in the RDoc::TopLevel
54
- # +location+.
42
+ ##
43
+ # Alias for text
55
44
 
56
- def initialize(text = nil, location = nil, language = nil)
57
- @location = location
58
- @text = text.nil? ? nil : text.dup
59
- @language = language
45
+ alias to_s text
60
46
 
61
- @document = nil
62
- @format = 'rdoc'
63
- @normalized = false
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
- def initialize_copy(copy) # :nodoc:
71
- @text = copy.text.dup
72
- end
53
+ ##
54
+ # Creates a new comment with +text+ that is found in the RDoc::TopLevel
55
+ # +location+.
73
56
 
74
- def ==(other) # :nodoc:
75
- self.class === other and
76
- other.text == @text and other.location == @location
77
- end
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
- # Look for a 'call-seq' in the comment to override the normal parameter
81
- # handling. The :call-seq: is indented from the baseline. All lines of the
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
- # A comment is empty if its text String is empty.
67
+ ##
68
+ #--
69
+ # TODO deep copy @document
124
70
 
125
- def empty?
126
- @text.empty? && (@document.nil? || @document.empty?)
127
- end
71
+ def initialize_copy(copy) # :nodoc:
72
+ @text = copy.text.dup
73
+ end
128
74
 
129
- ##
130
- # HACK dubious
75
+ def ==(other) # :nodoc:
76
+ self.class === other and
77
+ other.text == @text and other.location == @location
78
+ end
131
79
 
132
- def encode!(encoding)
133
- @text = String.new @text, encoding: encoding
134
- self
135
- end
80
+ ##
81
+ # A comment is empty if its text String is empty.
136
82
 
137
- ##
138
- # Sets the format of this comment and resets any parsed document
83
+ def empty?
84
+ @text.empty? && (@document.nil? || @document.empty?)
85
+ end
139
86
 
140
- def format=(format)
141
- @format = format
142
- @document = nil
143
- end
87
+ ##
88
+ # HACK dubious
144
89
 
145
- def inspect # :nodoc:
146
- location = @location ? @location.relative_name : '(unknown)'
90
+ def encode!(encoding)
91
+ @text = String.new @text, encoding: encoding
92
+ self
93
+ end
147
94
 
148
- "#<%s:%x %s %p>" % [self.class, object_id, location, @text]
149
- end
95
+ ##
96
+ # Sets the format of this comment and resets any parsed document
150
97
 
151
- ##
152
- # Normalizes the text. See RDoc::Text#normalize_comment for details
98
+ def format=(format)
99
+ @format = format
100
+ @document = nil
101
+ end
153
102
 
154
- def normalize
155
- return self unless @text
156
- return self if @normalized # TODO eliminate duplicate normalization
103
+ def inspect # :nodoc:
104
+ location = @location ? @location.relative_name : '(unknown)'
157
105
 
158
- @text = normalize_comment @text
106
+ "#<%s:%x %s %p>" % [self.class, object_id, location, @text]
107
+ end
159
108
 
160
- @normalized = true
109
+ ##
110
+ # Normalizes the text. See RDoc::Text#normalize_comment for details
161
111
 
162
- self
163
- end
112
+ def normalize
113
+ return self unless @text
114
+ return self if @normalized # TODO eliminate duplicate normalization
164
115
 
165
- # Change normalized, when creating already normalized comment.
116
+ @text = normalize_comment @text
166
117
 
167
- def normalized=(value)
168
- @normalized = value
169
- end
118
+ @normalized = true
170
119
 
171
- ##
172
- # Was this text normalized?
120
+ self
121
+ end
173
122
 
174
- def normalized? # :nodoc:
175
- @normalized
176
- end
123
+ # Change normalized, when creating already normalized comment.
177
124
 
178
- ##
179
- # Parses the comment into an RDoc::Markup::Document. The parsed document is
180
- # cached until the text is changed.
125
+ def normalized=(value)
126
+ @normalized = value
127
+ end
181
128
 
182
- def parse
183
- return @document if @document
129
+ ##
130
+ # Was this text normalized?
184
131
 
185
- @document = super @text, @format
186
- @document.file = @location
187
- @document
188
- end
132
+ def normalized? # :nodoc:
133
+ @normalized
134
+ end
189
135
 
190
- ##
191
- # Removes private sections from this comment. Private sections are flush to
192
- # the comment marker and start with <tt>--</tt> and end with <tt>++</tt>.
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
- # Replaces this comment's text with +text+ and resets the parsed document.
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
- def text=(text)
218
- raise RDoc::Error, 'replacing document-only comment is not allowed' if
219
- @text.nil? and @document
143
+ @document = super @text, @format
144
+ @document.file = @location
145
+ @document
146
+ end
220
147
 
221
- @document = nil
222
- @text = text.nil? ? nil : text.dup
223
- end
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
- # Returns true if this comment is in TomDoc format.
153
+ def text=(text)
154
+ raise Error, 'replacing document-only comment is not allowed' if
155
+ @text.nil? and @document
227
156
 
228
- def tomdoc?
229
- @format == 'tomdoc'
230
- end
157
+ @document = nil
158
+ @text = text.nil? ? nil : text.dup
159
+ end
231
160
 
232
- MULTILINE_DIRECTIVES = %w[call-seq].freeze # :nodoc:
161
+ ##
162
+ # Returns true if this comment is in TomDoc format.
233
163
 
234
- # There are more, but already handled by RDoc::Parser::C
235
- COLON_LESS_DIRECTIVES = %w[call-seq Document-method].freeze # :nodoc:
164
+ def tomdoc?
165
+ @format == 'tomdoc'
166
+ end
236
167
 
237
- DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP = /\A(?<colon>\\?:|:?)(?<directive>[\w-]+):(?<param>.*)/
168
+ MULTILINE_DIRECTIVES = %w[call-seq].freeze # :nodoc:
238
169
 
239
- private_constant :MULTILINE_DIRECTIVES, :COLON_LESS_DIRECTIVES, :DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP
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
- class << self
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
- 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
177
+ class << self
252
178
 
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*/
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
- 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
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
- prefix = line[indent_regexp]
317
- prefix_indent = ' ' * prefix.size
318
- line = line.byteslice(prefix.bytesize..)
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
- 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
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
- 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)
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
- 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]
290
+ line_no += read_lines
353
291
  end
354
- line_no += read_lines
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
- normalized_comment = String.new(encoding: text.encoding) << normalize_comment_lines(comment_lines).join("\n")
358
- [normalized_comment, directives]
359
- end
297
+ # Remove preceding indent spaces and blank lines from the comment lines
360
298
 
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
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
- # Take value lines of multiline directive
315
+ # Take value lines of multiline directive
380
316
 
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?
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
- first_indent_size = lines.first.match(indent_regexp).end(0)
320
+ first_indent_size = lines.first.match(indent_regexp).end(0)
385
321
 
386
- # Blank line or unindented line is not part of multiline-directive value
387
- return [] if first_indent_size <= base_indent_size
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
- 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
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
- end
408
- value_lines.map! { |l| (l[first_indent_size..] || '').chomp }
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
- if value_lines.size != lines.size && !value_lines.last.empty?
411
- warn "#{filename}:#{line_no} Multiline directive :#{directive}: should end with a blank line."
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