rdoc 6.3.4.1 → 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 +195 -0
- data/History.rdoc +65 -63
- data/LEGAL.rdoc +7 -1
- data/LICENSE.rdoc +6 -0
- data/README.md +236 -0
- data/RI.md +842 -0
- data/TODO.rdoc +8 -7
- data/doc/markup_reference/markdown.md +659 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/exe/rdoc +0 -1
- data/lib/rdoc/{alias.rb → code_object/alias.rb} +4 -18
- data/lib/rdoc/{any_method.rb → code_object/any_method.rb} +50 -24
- data/lib/rdoc/{attr.rb → code_object/attr.rb} +16 -14
- data/lib/rdoc/{class_module.rb → code_object/class_module.rb} +225 -58
- data/lib/rdoc/{constant.rb → code_object/constant.rb} +44 -10
- data/lib/rdoc/code_object/context/section.rb +182 -0
- data/lib/rdoc/{context.rb → code_object/context.rb} +78 -106
- data/lib/rdoc/{extend.rb → code_object/extend.rb} +0 -1
- data/lib/rdoc/{include.rb → code_object/include.rb} +0 -1
- data/lib/rdoc/{method_attr.rb → code_object/method_attr.rb} +46 -48
- data/lib/rdoc/{mixin.rb → code_object/mixin.rb} +6 -4
- data/lib/rdoc/{normal_class.rb → code_object/normal_class.rb} +2 -3
- data/lib/rdoc/{normal_module.rb → code_object/normal_module.rb} +2 -3
- data/lib/rdoc/{require.rb → code_object/require.rb} +1 -2
- data/lib/rdoc/{single_class.rb → code_object/single_class.rb} +5 -1
- data/lib/rdoc/{top_level.rb → code_object/top_level.rb} +60 -63
- data/lib/rdoc/code_object.rb +11 -39
- data/lib/rdoc/code_objects.rb +1 -2
- data/lib/rdoc/comment.rb +202 -99
- data/lib/rdoc/cross_reference.rb +75 -62
- data/lib/rdoc/encoding.rb +8 -24
- data/lib/rdoc/erb_partial.rb +1 -2
- data/lib/rdoc/erbio.rb +3 -8
- data/lib/rdoc/generator/aliki.rb +200 -0
- data/lib/rdoc/generator/darkfish.rb +156 -122
- data/lib/rdoc/generator/json_index.rb +8 -24
- data/lib/rdoc/generator/markup.rb +70 -34
- data/lib/rdoc/generator/pot/message_extractor.rb +7 -7
- data/lib/rdoc/generator/pot/po.rb +1 -1
- data/lib/rdoc/generator/pot/po_entry.rb +8 -8
- data/lib/rdoc/generator/pot.rb +1 -5
- data/lib/rdoc/generator/ri.rb +1 -2
- data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
- 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 +163 -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 +27 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +27 -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 +230 -0
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +2181 -0
- data/lib/rdoc/generator/template/aliki/index.rhtml +22 -0
- data/lib/rdoc/generator/template/aliki/js/aliki.js +513 -0
- data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -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/_footer.rhtml +3 -3
- data/lib/rdoc/generator/template/darkfish/_head.rhtml +35 -14
- data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +1 -5
- data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +11 -9
- data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +11 -9
- data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +7 -6
- data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +20 -11
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +25 -5
- data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +4 -9
- data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +2 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +4 -4
- data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +28 -7
- data/lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml +3 -0
- data/lib/rdoc/generator/template/darkfish/class.rhtml +138 -90
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +420 -358
- data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/index.rhtml +14 -12
- data/lib/rdoc/generator/template/darkfish/js/darkfish.js +59 -3
- data/lib/rdoc/generator/template/darkfish/js/search.js +15 -5
- data/lib/rdoc/generator/template/darkfish/page.rhtml +7 -6
- data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +12 -9
- data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +24 -21
- data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +35 -21
- data/lib/rdoc/generator/template/json_index/js/navigation.js +8 -8
- data/lib/rdoc/generator/template/json_index/js/searcher.js +48 -6
- data/lib/rdoc/generator.rb +6 -5
- data/lib/rdoc/i18n/text.rb +3 -3
- data/lib/rdoc/i18n.rb +1 -1
- data/lib/rdoc/known_classes.rb +5 -4
- data/lib/rdoc/markdown/entities.rb +0 -1
- data/lib/rdoc/markdown/literals.kpeg +0 -2
- data/lib/rdoc/markdown/literals.rb +0 -1
- data/lib/rdoc/markdown.kpeg +140 -62
- data/lib/rdoc/markdown.rb +1015 -873
- data/lib/rdoc/markup/blank_line.rb +25 -24
- data/lib/rdoc/markup/block_quote.rb +1 -2
- data/lib/rdoc/markup/document.rb +10 -11
- data/lib/rdoc/markup/element.rb +21 -0
- data/lib/rdoc/markup/formatter.rb +134 -115
- data/lib/rdoc/markup/hard_break.rb +30 -28
- data/lib/rdoc/markup/heading.rb +163 -72
- data/lib/rdoc/markup/include.rb +3 -4
- data/lib/rdoc/markup/indented_paragraph.rb +4 -5
- data/lib/rdoc/markup/inline_parser.rb +312 -0
- data/lib/rdoc/markup/list.rb +6 -7
- data/lib/rdoc/markup/list_item.rb +6 -7
- data/lib/rdoc/markup/paragraph.rb +2 -3
- data/lib/rdoc/markup/parser.rb +29 -19
- data/lib/rdoc/markup/pre_process.rb +39 -18
- data/lib/rdoc/markup/raw.rb +52 -56
- data/lib/rdoc/markup/rule.rb +2 -3
- data/lib/rdoc/markup/table.rb +49 -32
- data/lib/rdoc/markup/to_ansi.rb +58 -8
- data/lib/rdoc/markup/to_bs.rb +47 -38
- data/lib/rdoc/markup/to_html.rb +343 -105
- data/lib/rdoc/markup/to_html_crossref.rb +143 -58
- data/lib/rdoc/markup/to_html_snippet.rb +78 -76
- data/lib/rdoc/markup/to_joined_paragraph.rb +3 -9
- data/lib/rdoc/markup/to_label.rb +34 -25
- data/lib/rdoc/markup/to_markdown.rb +74 -51
- data/lib/rdoc/markup/to_rdoc.rb +141 -82
- data/lib/rdoc/markup/to_table_of_contents.rb +4 -5
- data/lib/rdoc/markup/to_test.rb +10 -3
- data/lib/rdoc/markup/to_tt_only.rb +17 -31
- data/lib/rdoc/markup/verbatim.rb +5 -6
- data/lib/rdoc/markup.rb +59 -707
- data/lib/rdoc/options.rb +228 -101
- data/lib/rdoc/parser/c.rb +186 -184
- data/lib/rdoc/parser/changelog.rb +57 -13
- data/lib/rdoc/parser/markdown.rb +0 -2
- data/lib/rdoc/parser/rbs.rb +275 -0
- data/lib/rdoc/parser/rd.rb +0 -1
- data/lib/rdoc/parser/ruby.rb +963 -2024
- data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
- data/lib/rdoc/parser/simple.rb +6 -23
- data/lib/rdoc/parser/text.rb +0 -1
- data/lib/rdoc/parser.rb +35 -14
- data/lib/rdoc/rbs_helper.rb +186 -0
- data/lib/rdoc/rd/block_parser.rb +659 -11
- data/lib/rdoc/rd/block_parser.ry +13 -9
- data/lib/rdoc/rd/inline.rb +4 -5
- data/lib/rdoc/rd/inline_parser.rb +646 -2
- data/lib/rdoc/rd.rb +4 -5
- data/lib/rdoc/rdoc.rb +234 -90
- data/lib/rdoc/ri/driver.rb +172 -172
- data/lib/rdoc/ri/paths.rb +3 -3
- data/lib/rdoc/{servlet.rb → ri/servlet.rb} +28 -27
- data/lib/rdoc/ri/store.rb +0 -1
- data/lib/rdoc/ri/task.rb +3 -3
- data/lib/rdoc/ri.rb +5 -5
- data/lib/rdoc/rubygems_hook.rb +106 -25
- data/lib/rdoc/server.rb +460 -0
- data/lib/rdoc/stats/normal.rb +1 -1
- data/lib/rdoc/stats/quiet.rb +1 -2
- data/lib/rdoc/stats/verbose.rb +3 -5
- data/lib/rdoc/stats.rb +158 -136
- data/lib/rdoc/store.rb +267 -48
- data/lib/rdoc/task.rb +54 -28
- data/lib/rdoc/text.rb +60 -120
- data/lib/rdoc/token_stream.rb +30 -45
- data/lib/rdoc/tom_doc.rb +9 -15
- data/lib/rdoc/version.rb +3 -1
- data/lib/rdoc.rb +90 -52
- data/lib/rubygems_plugin.rb +14 -0
- data/man/ri.1 +2 -0
- data/rdoc-logo.svg +43 -0
- data/rdoc.gemspec +25 -200
- metadata +120 -53
- data/CONTRIBUTING.rdoc +0 -220
- data/ExampleMarkdown.md +0 -37
- data/ExampleRDoc.rdoc +0 -208
- data/Gemfile +0 -12
- data/README.rdoc +0 -129
- data/RI.rdoc +0 -57
- data/Rakefile +0 -101
- data/bin/console +0 -7
- data/bin/setup +0 -6
- data/lib/rdoc/anon_class.rb +0 -11
- data/lib/rdoc/context/section.rb +0 -232
- data/lib/rdoc/generator/template/darkfish/.document +0 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +0 -19
- data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +0 -9
- data/lib/rdoc/generator/template/json_index/.document +0 -1
- data/lib/rdoc/ghost_method.rb +0 -7
- data/lib/rdoc/markup/attr_changer.rb +0 -23
- data/lib/rdoc/markup/attr_span.rb +0 -36
- data/lib/rdoc/markup/attribute_manager.rb +0 -409
- data/lib/rdoc/markup/attributes.rb +0 -71
- data/lib/rdoc/markup/regexp_handling.rb +0 -41
- data/lib/rdoc/meta_method.rb +0 -7
- data/lib/rdoc/parser/ripper_state_lex.rb +0 -590
- data/lib/rdoc/parser/ruby_tools.rb +0 -167
data/lib/rdoc/parser/ruby.rb
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
# ruby-token.rb - ruby tokens
|
|
8
|
-
# by Keiju ISHITSUKA (Nippon Rational Inc.)
|
|
9
|
-
#
|
|
2
|
+
|
|
3
|
+
require 'prism'
|
|
4
|
+
require_relative '../rbs_helper'
|
|
5
|
+
|
|
6
|
+
# Parse and collect document from Ruby source code.
|
|
10
7
|
|
|
11
8
|
##
|
|
12
9
|
# Extracts code elements from a source file returning a TopLevel object
|
|
13
10
|
# containing the constituent file elements.
|
|
14
11
|
#
|
|
15
|
-
# This file is based on rtags
|
|
16
|
-
#
|
|
17
12
|
# RubyParser understands how to document:
|
|
18
13
|
# * classes
|
|
19
14
|
# * modules
|
|
@@ -32,10 +27,6 @@
|
|
|
32
27
|
#
|
|
33
28
|
# == Method Arguments
|
|
34
29
|
#
|
|
35
|
-
#--
|
|
36
|
-
# NOTE: I don't think this works, needs tests, remove the paragraph following
|
|
37
|
-
# this block when known to work
|
|
38
|
-
#
|
|
39
30
|
# The parser extracts the arguments from the method definition. You can
|
|
40
31
|
# override this with a custom argument definition using the :args: directive:
|
|
41
32
|
#
|
|
@@ -49,11 +40,6 @@
|
|
|
49
40
|
#
|
|
50
41
|
# If you have a more-complex set of overrides you can use the :call-seq:
|
|
51
42
|
# directive:
|
|
52
|
-
#++
|
|
53
|
-
#
|
|
54
|
-
# The parser extracts the arguments from the method definition. You can
|
|
55
|
-
# override this with a custom argument definition using the :call-seq:
|
|
56
|
-
# directive:
|
|
57
43
|
#
|
|
58
44
|
# ##
|
|
59
45
|
# # This method can be called with a range or an offset and length
|
|
@@ -80,16 +66,16 @@
|
|
|
80
66
|
# == Metaprogrammed Methods
|
|
81
67
|
#
|
|
82
68
|
# To pick up a metaprogrammed method, the parser looks for a comment starting
|
|
83
|
-
# with '##' before
|
|
69
|
+
# with '##' before a metaprogramming method call:
|
|
84
70
|
#
|
|
85
71
|
# ##
|
|
86
72
|
# # This is a meta-programmed method!
|
|
87
73
|
#
|
|
88
74
|
# add_my_method :meta_method, :arg1, :arg2
|
|
89
75
|
#
|
|
90
|
-
# The parser looks at the
|
|
76
|
+
# The parser looks at the first argument to determine the name, in
|
|
91
77
|
# this example, :meta_method. If a name cannot be found, a warning is printed
|
|
92
|
-
# and 'unknown is used.
|
|
78
|
+
# and 'unknown' is used.
|
|
93
79
|
#
|
|
94
80
|
# You can force the name of a method using the :method: directive:
|
|
95
81
|
#
|
|
@@ -108,7 +94,7 @@
|
|
|
108
94
|
# # :singleton-method: some_method!
|
|
109
95
|
#
|
|
110
96
|
# You can define arguments for metaprogrammed methods via either the
|
|
111
|
-
#
|
|
97
|
+
# \:call-seq:, :arg: or :args: directives.
|
|
112
98
|
#
|
|
113
99
|
# Additionally you can mark a method as an attribute by
|
|
114
100
|
# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like
|
|
@@ -138,2190 +124,1143 @@
|
|
|
138
124
|
# Note that by default, the :method: directive will be ignored if there is a
|
|
139
125
|
# standard rdocable item following it.
|
|
140
126
|
|
|
141
|
-
require 'ripper'
|
|
142
|
-
require_relative 'ripper_state_lex'
|
|
143
|
-
|
|
144
127
|
class RDoc::Parser::Ruby < RDoc::Parser
|
|
145
128
|
|
|
146
129
|
parse_files_matching(/\.rbw?$/)
|
|
147
130
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
##
|
|
152
|
-
# RDoc::NormalClass type
|
|
131
|
+
# Matches an RBS inline type annotation line: #: followed by whitespace
|
|
132
|
+
RBS_SIG_LINE = /\A#:\s/ # :nodoc:
|
|
153
133
|
|
|
154
|
-
|
|
134
|
+
attr_accessor :visibility
|
|
135
|
+
attr_reader :container, :singleton, :in_proc_block
|
|
155
136
|
|
|
156
|
-
|
|
157
|
-
# RDoc::SingleClass type
|
|
158
|
-
|
|
159
|
-
SINGLE = "<<"
|
|
160
|
-
|
|
161
|
-
##
|
|
162
|
-
# Creates a new Ruby parser.
|
|
163
|
-
|
|
164
|
-
def initialize(top_level, file_name, content, options, stats)
|
|
137
|
+
def initialize(top_level, content, options, stats)
|
|
165
138
|
super
|
|
166
139
|
|
|
167
|
-
|
|
168
|
-
tab_width = @options.tab_width
|
|
169
|
-
content = content.split(/\n/).map do |line|
|
|
170
|
-
1 while line.gsub!(/\t+/) {
|
|
171
|
-
' ' * (tab_width*$&.length - $`.length % tab_width)
|
|
172
|
-
} && $~
|
|
173
|
-
line
|
|
174
|
-
end.join("\n")
|
|
175
|
-
end
|
|
140
|
+
content = handle_tab_width(content)
|
|
176
141
|
|
|
177
142
|
@size = 0
|
|
178
143
|
@token_listeners = nil
|
|
179
144
|
content = RDoc::Encoding.remove_magic_comment content
|
|
180
|
-
@scanner = RDoc::Parser::RipperStateLex.parse(content)
|
|
181
145
|
@content = content
|
|
182
|
-
@scanner_point = 0
|
|
183
|
-
@prev_seek = nil
|
|
184
146
|
@markup = @options.markup
|
|
185
147
|
@track_visibility = :nodoc != @options.visibility
|
|
186
148
|
@encoding = @options.encoding
|
|
187
149
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
|
|
199
|
-
def
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
#
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
singleton =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
when 'public_class_method' then
|
|
226
|
-
singleton = true
|
|
227
|
-
:public
|
|
228
|
-
when 'module_function' then
|
|
229
|
-
singleton = true
|
|
230
|
-
:public
|
|
231
|
-
else
|
|
232
|
-
raise RDoc::Error, "Invalid visibility: #{tk.name}"
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
return vis_type, vis, singleton
|
|
150
|
+
@module_nesting = [[top_level, false]]
|
|
151
|
+
@container = top_level
|
|
152
|
+
@visibility = :public
|
|
153
|
+
@singleton = false
|
|
154
|
+
@in_proc_block = false
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Suppress `extend` and `include` within block
|
|
158
|
+
# because they might be a metaprogramming block
|
|
159
|
+
# example: `Module.new { include M }` `M.module_eval { include N }`
|
|
160
|
+
|
|
161
|
+
def with_in_proc_block
|
|
162
|
+
in_proc_block = @in_proc_block
|
|
163
|
+
@in_proc_block = true
|
|
164
|
+
yield
|
|
165
|
+
@in_proc_block = in_proc_block
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Dive into another container
|
|
169
|
+
|
|
170
|
+
def with_container(container, singleton: false)
|
|
171
|
+
old_container = @container
|
|
172
|
+
old_visibility = @visibility
|
|
173
|
+
old_singleton = @singleton
|
|
174
|
+
old_in_proc_block = @in_proc_block
|
|
175
|
+
@visibility = :public
|
|
176
|
+
@container = container
|
|
177
|
+
@singleton = singleton
|
|
178
|
+
@in_proc_block = false
|
|
179
|
+
@module_nesting.push([container, singleton])
|
|
180
|
+
yield container
|
|
181
|
+
ensure
|
|
182
|
+
@container = old_container
|
|
183
|
+
@visibility = old_visibility
|
|
184
|
+
@singleton = old_singleton
|
|
185
|
+
@in_proc_block = old_in_proc_block
|
|
186
|
+
@module_nesting.pop
|
|
236
187
|
end
|
|
237
188
|
|
|
238
|
-
|
|
239
|
-
#
|
|
240
|
-
|
|
241
|
-
def collect_first_comment
|
|
242
|
-
skip_tkspace
|
|
243
|
-
comment = ''.dup
|
|
244
|
-
comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
|
|
245
|
-
first_line = true
|
|
246
|
-
first_comment_tk_kind = nil
|
|
247
|
-
line_no = nil
|
|
248
|
-
|
|
249
|
-
tk = get_tk
|
|
250
|
-
|
|
251
|
-
while tk && (:on_comment == tk[:kind] or :on_embdoc == tk[:kind])
|
|
252
|
-
comment_body = retrieve_comment_body(tk)
|
|
253
|
-
if first_line and comment_body =~ /\A#!/ then
|
|
254
|
-
skip_tkspace
|
|
255
|
-
tk = get_tk
|
|
256
|
-
elsif first_line and comment_body =~ /\A#\s*-\*-/ then
|
|
257
|
-
first_line = false
|
|
258
|
-
skip_tkspace
|
|
259
|
-
tk = get_tk
|
|
260
|
-
else
|
|
261
|
-
break if first_comment_tk_kind and not first_comment_tk_kind === tk[:kind]
|
|
262
|
-
first_comment_tk_kind = tk[:kind]
|
|
263
|
-
|
|
264
|
-
line_no = tk[:line_no] if first_line
|
|
265
|
-
first_line = false
|
|
266
|
-
comment << comment_body
|
|
267
|
-
tk = get_tk
|
|
189
|
+
# Records the location of this +container+ in the file for this parser and
|
|
190
|
+
# adds it to the list of classes and modules in the file.
|
|
268
191
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
end
|
|
192
|
+
def record_location(container) # :nodoc:
|
|
193
|
+
case container
|
|
194
|
+
when RDoc::ClassModule then
|
|
195
|
+
@top_level.add_to_classes_or_modules container
|
|
274
196
|
end
|
|
275
197
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
new_comment comment, line_no
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
##
|
|
282
|
-
# Consumes trailing whitespace from the token stream
|
|
283
|
-
|
|
284
|
-
def consume_trailing_spaces # :nodoc:
|
|
285
|
-
skip_tkspace_without_nl
|
|
198
|
+
container.record_location @top_level
|
|
286
199
|
end
|
|
287
200
|
|
|
288
|
-
|
|
289
|
-
# Creates a new attribute in +container+ with +name+.
|
|
290
|
-
|
|
291
|
-
def create_attr container, single, name, rw, comment # :nodoc:
|
|
292
|
-
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
|
|
293
|
-
record_location att
|
|
294
|
-
|
|
295
|
-
container.add_attribute att
|
|
296
|
-
@stats.add_attribute att
|
|
297
|
-
|
|
298
|
-
att
|
|
299
|
-
end
|
|
201
|
+
# Scans this Ruby file for Ruby constructs
|
|
300
202
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
203
|
+
def scan
|
|
204
|
+
@lines = @content.lines
|
|
205
|
+
result = Prism.parse_lex(@content)
|
|
206
|
+
@program_node, unordered_tokens = result.value
|
|
207
|
+
# Heredoc tokens are not in start_offset order.
|
|
208
|
+
# Need to sort them to use bsearch for finding tokens from location.
|
|
209
|
+
@prism_tokens = unordered_tokens.map(&:first).sort_by { |t| t.location.start_offset }
|
|
210
|
+
@line_nodes = {}
|
|
211
|
+
prepare_line_nodes(@program_node)
|
|
212
|
+
prepare_comments(result.comments)
|
|
213
|
+
return if @top_level.done_documenting
|
|
304
214
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
container.find_module_named rhs_name
|
|
310
|
-
end
|
|
215
|
+
@first_non_meta_comment_start_line = nil
|
|
216
|
+
if (_line_no, start_line = @unprocessed_comments.first)
|
|
217
|
+
@first_non_meta_comment_start_line = start_line if start_line < @program_node.location.start_line
|
|
218
|
+
end
|
|
311
219
|
|
|
312
|
-
|
|
220
|
+
@program_node.accept(RDocVisitor.new(self, @top_level, @store))
|
|
221
|
+
process_comments_until(@lines.size + 1)
|
|
313
222
|
end
|
|
314
223
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
msg = make_message msg
|
|
320
|
-
|
|
321
|
-
abort msg
|
|
224
|
+
def should_document?(code_object) # :nodoc:
|
|
225
|
+
return true unless @track_visibility
|
|
226
|
+
return false if code_object.parent&.document_children == false
|
|
227
|
+
code_object.document_self
|
|
322
228
|
end
|
|
323
229
|
|
|
324
|
-
|
|
325
|
-
#
|
|
230
|
+
# Assign AST node to a line.
|
|
231
|
+
# This is used to show meta-method source code in the documentation.
|
|
326
232
|
|
|
327
|
-
def
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
true
|
|
332
|
-
elsif :on_kw == tk[:kind] && ('false' == tk[:text] || 'nil' == tk[:text])
|
|
333
|
-
false
|
|
334
|
-
else
|
|
335
|
-
unget_tk tk
|
|
336
|
-
true
|
|
233
|
+
def prepare_line_nodes(node) # :nodoc:
|
|
234
|
+
case node
|
|
235
|
+
when Prism::CallNode, Prism::DefNode
|
|
236
|
+
@line_nodes[node.location.start_line] ||= node
|
|
337
237
|
end
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
##
|
|
341
|
-
# Look for the name of a class of module (optionally with a leading :: or
|
|
342
|
-
# with :: separated named) and return the ultimate name, the associated
|
|
343
|
-
# container, and the given name (with the ::).
|
|
344
|
-
|
|
345
|
-
def get_class_or_module container, ignore_constants = false
|
|
346
|
-
skip_tkspace
|
|
347
|
-
name_t = get_tk
|
|
348
|
-
given_name = ''.dup
|
|
349
|
-
|
|
350
|
-
# class ::A -> A is in the top level
|
|
351
|
-
if :on_op == name_t[:kind] and '::' == name_t[:text] then # bug
|
|
352
|
-
name_t = get_tk
|
|
353
|
-
container = @top_level
|
|
354
|
-
given_name << '::'
|
|
238
|
+
node.compact_child_nodes.each do |child|
|
|
239
|
+
prepare_line_nodes(child)
|
|
355
240
|
end
|
|
241
|
+
end
|
|
356
242
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
name_t = get_tk
|
|
387
|
-
unless :on_const == name_t[:kind] || :on_ident == name_t[:kind]
|
|
388
|
-
raise RDoc::Error, "Invalid class or module definition: #{given_name}"
|
|
389
|
-
end
|
|
390
|
-
if prev_container == container and !ignore_constants
|
|
391
|
-
given_name = name_t[:text]
|
|
243
|
+
# Prepares comments for processing. Comments are grouped into consecutive.
|
|
244
|
+
# Consecutive comment is linked to the next non-blank line.
|
|
245
|
+
#
|
|
246
|
+
# Example:
|
|
247
|
+
# 01| class A # modifier comment 1
|
|
248
|
+
# 02| def foo; end # modifier comment 2
|
|
249
|
+
# 03|
|
|
250
|
+
# 04| # consecutive comment 1 start_line: 4
|
|
251
|
+
# 05| # consecutive comment 1 linked to line: 7
|
|
252
|
+
# 06|
|
|
253
|
+
# 07| # consecutive comment 2 start_line: 7
|
|
254
|
+
# 08| # consecutive comment 2 linked to line: 10
|
|
255
|
+
# 09|
|
|
256
|
+
# 10| def bar; end # consecutive comment 2 linked to this line
|
|
257
|
+
# 11| end
|
|
258
|
+
|
|
259
|
+
def prepare_comments(comments)
|
|
260
|
+
current = []
|
|
261
|
+
consecutive_comments = [current]
|
|
262
|
+
@modifier_comments = {}
|
|
263
|
+
comments.each do |comment|
|
|
264
|
+
if comment.is_a? Prism::EmbDocComment
|
|
265
|
+
consecutive_comments << [comment] << (current = [])
|
|
266
|
+
elsif comment.location.start_line_slice.match?(/\S/)
|
|
267
|
+
text = comment.slice
|
|
268
|
+
text = RDoc::Encoding.change_encoding(text, @encoding) if @encoding
|
|
269
|
+
@modifier_comments[comment.location.start_line] = text
|
|
270
|
+
elsif current.empty? || current.last.location.end_line + 1 == comment.location.start_line
|
|
271
|
+
current << comment
|
|
392
272
|
else
|
|
393
|
-
|
|
273
|
+
consecutive_comments << (current = [comment])
|
|
394
274
|
end
|
|
395
275
|
end
|
|
276
|
+
consecutive_comments.reject!(&:empty?)
|
|
277
|
+
|
|
278
|
+
# Example: line_no = 5, start_line = 2, comment_text = "# comment_start_line\n# comment\n"
|
|
279
|
+
# 1| class A
|
|
280
|
+
# 2| # comment_start_line
|
|
281
|
+
# 3| # comment
|
|
282
|
+
# 4|
|
|
283
|
+
# 5| def f; end # comment linked to this line
|
|
284
|
+
# 6| end
|
|
285
|
+
@unprocessed_comments = consecutive_comments.map! do |comments|
|
|
286
|
+
start_line = comments.first.location.start_line
|
|
287
|
+
line_no = comments.last.location.end_line + (comments.last.location.end_column == 0 ? 0 : 1)
|
|
288
|
+
texts = comments.map do |c|
|
|
289
|
+
c.is_a?(Prism::EmbDocComment) ? c.slice.lines[1...-1].join : c.slice
|
|
290
|
+
end
|
|
291
|
+
text = texts.join("\n")
|
|
292
|
+
text = RDoc::Encoding.change_encoding(text, @encoding) if @encoding
|
|
293
|
+
line_no += 1 while @lines[line_no - 1]&.match?(/\A\s*$/)
|
|
294
|
+
[line_no, start_line, text]
|
|
295
|
+
end
|
|
396
296
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
# Return a superclass, which can be either a constant of an expression
|
|
404
|
-
|
|
405
|
-
def get_class_specification
|
|
406
|
-
tk = peek_tk
|
|
407
|
-
if tk.nil?
|
|
408
|
-
return ''
|
|
409
|
-
elsif :on_kw == tk[:kind] && 'self' == tk[:text]
|
|
410
|
-
return 'self'
|
|
411
|
-
elsif :on_gvar == tk[:kind]
|
|
412
|
-
return ''
|
|
297
|
+
# The first comment is special. It defines markup for the rest of the comments.
|
|
298
|
+
_, first_comment_start_line, first_comment_text = @unprocessed_comments.first
|
|
299
|
+
if first_comment_text && @lines[0...first_comment_start_line - 1].all? { |l| l.match?(/\A\s*$/) }
|
|
300
|
+
_text, directives = @preprocess.parse_comment(first_comment_text, first_comment_start_line, :ruby)
|
|
301
|
+
markup, = directives['markup']
|
|
302
|
+
@markup = markup.downcase if markup
|
|
413
303
|
end
|
|
304
|
+
end
|
|
414
305
|
|
|
415
|
-
|
|
306
|
+
# Creates an RDoc::Method on +container+ from +comment+ if there is a
|
|
307
|
+
# Signature section in the comment
|
|
416
308
|
|
|
417
|
-
|
|
309
|
+
def parse_comment_tomdoc(container, comment, line_no, start_line)
|
|
310
|
+
return unless signature = RDoc::TomDoc.signature(comment)
|
|
418
311
|
|
|
419
|
-
|
|
312
|
+
name, = signature.split %r%[ \(]%, 2
|
|
420
313
|
|
|
421
|
-
|
|
422
|
-
|
|
314
|
+
meth = RDoc::AnyMethod.new name
|
|
315
|
+
record_location(meth)
|
|
316
|
+
meth.line = start_line
|
|
317
|
+
meth.call_seq = signature
|
|
318
|
+
return unless meth.name
|
|
423
319
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
end
|
|
320
|
+
meth.start_collecting_tokens(:ruby)
|
|
321
|
+
node = @line_nodes[line_no]
|
|
322
|
+
tokens = node ? syntax_highlighted_tokens(node) : []
|
|
323
|
+
tokens.each { |token| meth.token_stream << token }
|
|
429
324
|
|
|
430
|
-
|
|
431
|
-
|
|
325
|
+
container.add_method meth
|
|
326
|
+
meth.comment = comment
|
|
327
|
+
@stats.add_method meth
|
|
432
328
|
end
|
|
433
329
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
# names
|
|
437
|
-
|
|
438
|
-
def get_constant
|
|
439
|
-
res = ""
|
|
440
|
-
skip_tkspace_without_nl
|
|
441
|
-
tk = get_tk
|
|
442
|
-
|
|
443
|
-
while tk && ((:on_op == tk[:kind] && '::' == tk[:text]) || :on_const == tk[:kind]) do
|
|
444
|
-
res += tk[:text]
|
|
445
|
-
tk = get_tk
|
|
446
|
-
end
|
|
447
|
-
|
|
448
|
-
unget_tk(tk)
|
|
449
|
-
res
|
|
330
|
+
def has_modifier_nodoc?(line_no) # :nodoc:
|
|
331
|
+
@modifier_comments[line_no]&.match?(/\A#\s*:nodoc:/)
|
|
450
332
|
end
|
|
451
333
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
skip_tkspace_without_nl
|
|
457
|
-
get_tkread
|
|
458
|
-
tk = get_tk
|
|
459
|
-
end_token = get_end_token tk
|
|
460
|
-
return '' unless end_token
|
|
461
|
-
|
|
462
|
-
nest = 0
|
|
463
|
-
continue = false
|
|
464
|
-
only_constant = true
|
|
465
|
-
|
|
466
|
-
while tk != nil do
|
|
467
|
-
is_element_of_constant = false
|
|
468
|
-
case tk[:kind]
|
|
469
|
-
when :on_semicolon then
|
|
470
|
-
break if nest == 0
|
|
471
|
-
when :on_lbracket then
|
|
472
|
-
nest += 1
|
|
473
|
-
when :on_rbracket then
|
|
474
|
-
nest -= 1
|
|
475
|
-
when :on_lbrace then
|
|
476
|
-
nest += 1
|
|
477
|
-
when :on_rbrace then
|
|
478
|
-
nest -= 1
|
|
479
|
-
if nest <= 0
|
|
480
|
-
# we might have a.each { |i| yield i }
|
|
481
|
-
unget_tk(tk) if nest < 0
|
|
482
|
-
break
|
|
483
|
-
end
|
|
484
|
-
when :on_lparen then
|
|
485
|
-
nest += 1
|
|
486
|
-
when end_token[:kind] then
|
|
487
|
-
if end_token[:kind] == :on_rparen
|
|
488
|
-
nest -= 1
|
|
489
|
-
break if nest <= 0
|
|
490
|
-
else
|
|
491
|
-
break if nest <= 0
|
|
492
|
-
end
|
|
493
|
-
when :on_rparen then
|
|
494
|
-
nest -= 1
|
|
495
|
-
when :on_comment, :on_embdoc then
|
|
496
|
-
@read.pop
|
|
497
|
-
if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and
|
|
498
|
-
(!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then
|
|
499
|
-
break if !continue and nest <= 0
|
|
500
|
-
end
|
|
501
|
-
when :on_comma then
|
|
502
|
-
continue = true
|
|
503
|
-
when :on_ident then
|
|
504
|
-
continue = false if continue
|
|
505
|
-
when :on_kw then
|
|
506
|
-
case tk[:text]
|
|
507
|
-
when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
|
|
508
|
-
nest += 1
|
|
509
|
-
when 'if', 'unless', 'while', 'until', 'rescue'
|
|
510
|
-
# postfix if/unless/while/until/rescue must be EXPR_LABEL
|
|
511
|
-
nest += 1 unless (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0
|
|
512
|
-
when 'end'
|
|
513
|
-
nest -= 1
|
|
514
|
-
break if nest == 0
|
|
515
|
-
end
|
|
516
|
-
when :on_const then
|
|
517
|
-
is_element_of_constant = true
|
|
518
|
-
when :on_op then
|
|
519
|
-
is_element_of_constant = true if '::' == tk[:text]
|
|
520
|
-
end
|
|
521
|
-
only_constant = false unless is_element_of_constant
|
|
522
|
-
tk = get_tk
|
|
523
|
-
end
|
|
524
|
-
|
|
525
|
-
if only_constant
|
|
526
|
-
get_tkread_clean(/\s+/, ' ')
|
|
527
|
-
else
|
|
528
|
-
''
|
|
334
|
+
def handle_modifier_directive(code_object, line_no) # :nodoc:
|
|
335
|
+
if (comment_text = @modifier_comments[line_no])
|
|
336
|
+
_text, directives = @preprocess.parse_comment(comment_text, line_no, :ruby)
|
|
337
|
+
handle_code_object_directives(code_object, directives)
|
|
529
338
|
end
|
|
530
339
|
end
|
|
531
340
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
when :on_lparen
|
|
543
|
-
token = RDoc::Parser::RipperStateLex::Token.new
|
|
544
|
-
token[:kind] = :on_rparen
|
|
545
|
-
token[:text] = ')'
|
|
546
|
-
token
|
|
547
|
-
when :on_rparen
|
|
548
|
-
nil
|
|
549
|
-
else
|
|
550
|
-
token = RDoc::Parser::RipperStateLex::Token.new
|
|
551
|
-
token[:kind] = :on_nl
|
|
552
|
-
token[:text] = "\n"
|
|
553
|
-
token
|
|
554
|
-
end
|
|
341
|
+
def call_node_name_arguments(call_node) # :nodoc:
|
|
342
|
+
return [] unless call_node.arguments
|
|
343
|
+
call_node.arguments.arguments.map do |arg|
|
|
344
|
+
case arg
|
|
345
|
+
when Prism::SymbolNode
|
|
346
|
+
arg.value
|
|
347
|
+
when Prism::StringNode
|
|
348
|
+
arg.unescaped
|
|
349
|
+
end
|
|
350
|
+
end || []
|
|
555
351
|
end
|
|
556
352
|
|
|
557
|
-
|
|
558
|
-
# Retrieves the method container for a singleton method.
|
|
353
|
+
# Handles meta method comments
|
|
559
354
|
|
|
560
|
-
def
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
355
|
+
def handle_meta_method_comment(comment, directives, node)
|
|
356
|
+
handle_code_object_directives(@container, directives)
|
|
357
|
+
is_call_node = node.is_a?(Prism::CallNode)
|
|
358
|
+
singleton_method = false
|
|
359
|
+
visibility = @visibility
|
|
360
|
+
attributes = rw = line_no = method_name = nil
|
|
361
|
+
directives.each do |directive, (param, line)|
|
|
362
|
+
case directive
|
|
363
|
+
when 'attr', 'attr_reader', 'attr_writer', 'attr_accessor'
|
|
364
|
+
attributes = [param] if param
|
|
365
|
+
attributes ||= call_node_name_arguments(node) if is_call_node
|
|
366
|
+
rw = directive == 'attr_writer' ? 'W' : directive == 'attr_accessor' ? 'RW' : 'R'
|
|
367
|
+
when 'method'
|
|
368
|
+
method_name = param if param
|
|
369
|
+
line_no = line
|
|
370
|
+
when 'singleton-method'
|
|
371
|
+
method_name = param if param
|
|
372
|
+
line_no = line
|
|
373
|
+
singleton_method = true
|
|
374
|
+
visibility = :public
|
|
572
375
|
end
|
|
573
376
|
end
|
|
574
377
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
unless [Class, Module].include?(obj.class) then
|
|
584
|
-
warn("Couldn't find #{name_t[:text]}. Assuming it's a module")
|
|
378
|
+
if attributes
|
|
379
|
+
attributes.each do |attr|
|
|
380
|
+
a = RDoc::Attr.new(attr, rw, comment, singleton: @singleton)
|
|
381
|
+
a.store = @store
|
|
382
|
+
a.line = line_no
|
|
383
|
+
record_location(a)
|
|
384
|
+
@container.add_attribute(a)
|
|
385
|
+
a.visibility = visibility
|
|
585
386
|
end
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
387
|
+
elsif line_no || node
|
|
388
|
+
method_name ||= call_node_name_arguments(node).first if is_call_node
|
|
389
|
+
if node
|
|
390
|
+
tokens = syntax_highlighted_tokens(node)
|
|
391
|
+
line_no = node.location.start_line
|
|
590
392
|
else
|
|
591
|
-
|
|
393
|
+
tokens = []
|
|
592
394
|
end
|
|
593
|
-
|
|
594
|
-
|
|
395
|
+
internal_add_method(
|
|
396
|
+
method_name,
|
|
397
|
+
@container,
|
|
398
|
+
comment: comment,
|
|
399
|
+
directives: directives,
|
|
400
|
+
dont_rename_initialize: false,
|
|
401
|
+
line_no: line_no,
|
|
402
|
+
visibility: visibility,
|
|
403
|
+
singleton: @singleton || singleton_method,
|
|
404
|
+
params: nil,
|
|
405
|
+
calls_super: false,
|
|
406
|
+
block_params: nil,
|
|
407
|
+
tokens: tokens,
|
|
408
|
+
)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
INVALID_GHOST_METHOD_ACCEPT_DIRECTIVE_LIST = %w[
|
|
413
|
+
method singleton-method attr attr_reader attr_writer attr_accessor
|
|
414
|
+
].freeze
|
|
415
|
+
private_constant :INVALID_GHOST_METHOD_ACCEPT_DIRECTIVE_LIST
|
|
416
|
+
|
|
417
|
+
def normal_comment_treat_as_ghost_method_for_now?(directives, line_no) # :nodoc:
|
|
418
|
+
# Meta method comment should start with `##` but some comments does not follow this rule.
|
|
419
|
+
# For now, RDoc accepts them as a meta method comment if there is no node linked to it.
|
|
420
|
+
!@line_nodes[line_no] && INVALID_GHOST_METHOD_ACCEPT_DIRECTIVE_LIST.any? { |directive| directives.has_key?(directive) }
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def handle_standalone_consecutive_comment_directive(comment, directives, start_with_sharp_sharp, line_no, start_line) # :nodoc:
|
|
424
|
+
if start_with_sharp_sharp && start_line != @first_non_meta_comment_start_line
|
|
425
|
+
node = @line_nodes[line_no]
|
|
426
|
+
handle_meta_method_comment(comment, directives, node)
|
|
427
|
+
elsif normal_comment_treat_as_ghost_method_for_now?(directives, line_no) && start_line != @first_non_meta_comment_start_line
|
|
428
|
+
handle_meta_method_comment(comment, directives, nil)
|
|
429
|
+
else
|
|
430
|
+
handle_code_object_directives(@container, directives)
|
|
595
431
|
end
|
|
596
|
-
|
|
597
|
-
container
|
|
598
432
|
end
|
|
599
433
|
|
|
600
|
-
|
|
601
|
-
# Extracts a name or symbol from the token stream.
|
|
602
|
-
|
|
603
|
-
def get_symbol_or_name
|
|
604
|
-
tk = get_tk
|
|
605
|
-
case tk[:kind]
|
|
606
|
-
when :on_symbol then
|
|
607
|
-
text = tk[:text].sub(/^:/, '')
|
|
434
|
+
# Processes consecutive comments that were not linked to any documentable code until the given line number
|
|
608
435
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
436
|
+
def process_comments_until(line_no_until)
|
|
437
|
+
while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
|
|
438
|
+
line_no, start_line, text = @unprocessed_comments.shift
|
|
439
|
+
if @markup == 'tomdoc'
|
|
440
|
+
comment = RDoc::Comment.new(text, @top_level, :ruby)
|
|
441
|
+
comment.format = 'tomdoc'
|
|
442
|
+
parse_comment_tomdoc(@container, comment, line_no, start_line)
|
|
443
|
+
@preprocess.run_post_processes(comment, @container)
|
|
444
|
+
elsif (comment_text, directives = parse_comment_text_to_directives(text, start_line))
|
|
445
|
+
handle_standalone_consecutive_comment_directive(comment_text, directives, text.start_with?(/#\#$/), line_no, start_line)
|
|
613
446
|
end
|
|
614
|
-
|
|
615
|
-
text
|
|
616
|
-
when :on_ident, :on_const, :on_gvar, :on_cvar, :on_ivar, :on_op, :on_kw then
|
|
617
|
-
tk[:text]
|
|
618
|
-
when :on_tstring, :on_dstring then
|
|
619
|
-
tk[:text][1..-2]
|
|
620
|
-
else
|
|
621
|
-
raise RDoc::Error, "Name or symbol expected (got #{tk})"
|
|
622
447
|
end
|
|
623
448
|
end
|
|
624
449
|
|
|
625
|
-
|
|
626
|
-
#
|
|
450
|
+
# Skips all undocumentable consecutive comments until the given line number.
|
|
451
|
+
# Undocumentable comments are comments written inside `def` or inside undocumentable class/module
|
|
627
452
|
|
|
628
|
-
def
|
|
629
|
-
while
|
|
630
|
-
|
|
631
|
-
container = container.parent
|
|
453
|
+
def skip_comments_until(line_no_until)
|
|
454
|
+
while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
|
|
455
|
+
@unprocessed_comments.shift
|
|
632
456
|
end
|
|
633
457
|
end
|
|
634
458
|
|
|
635
|
-
|
|
636
|
-
# Look for directives in a normal comment block:
|
|
637
|
-
#
|
|
638
|
-
# # :stopdoc:
|
|
639
|
-
# # Don't display comment from this point forward
|
|
640
|
-
#
|
|
641
|
-
# This routine modifies its +comment+ parameter.
|
|
642
|
-
|
|
643
|
-
def look_for_directives_in container, comment
|
|
644
|
-
@preprocess.handle comment, container do |directive, param|
|
|
645
|
-
case directive
|
|
646
|
-
when 'method', 'singleton-method',
|
|
647
|
-
'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
|
|
648
|
-
false # handled elsewhere
|
|
649
|
-
when 'section' then
|
|
650
|
-
break unless container.kind_of?(RDoc::Context)
|
|
651
|
-
container.set_current_section param, comment.dup
|
|
652
|
-
comment.text = ''
|
|
653
|
-
break
|
|
654
|
-
end
|
|
655
|
-
end
|
|
459
|
+
# Returns consecutive comment linked to the given line number
|
|
656
460
|
|
|
657
|
-
|
|
461
|
+
def consecutive_comment(line_no)
|
|
462
|
+
return unless @unprocessed_comments.first&.first == line_no
|
|
463
|
+
_line_no, start_line, text = @unprocessed_comments.shift
|
|
464
|
+
parse_comment_text_to_directives(text, start_line)
|
|
658
465
|
end
|
|
659
466
|
|
|
660
|
-
|
|
661
|
-
#
|
|
467
|
+
# Parses comment text and returns +[RDoc::Comment, directives, type_signature_lines]+,
|
|
468
|
+
# or +nil+ if the comment is a section header (which has no associated code
|
|
469
|
+
# object).
|
|
662
470
|
|
|
663
|
-
def
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
471
|
+
def parse_comment_text_to_directives(comment_text, start_line) # :nodoc:
|
|
472
|
+
type_signature_lines = extract_type_signature!(comment_text, start_line)
|
|
473
|
+
comment_text, directives = @preprocess.parse_comment(comment_text, start_line, :ruby)
|
|
474
|
+
comment = RDoc::Comment.new(comment_text, @top_level, :ruby)
|
|
475
|
+
comment.normalized = true
|
|
476
|
+
comment.line = start_line
|
|
477
|
+
markup, = directives['markup']
|
|
478
|
+
comment.format = markup&.downcase || @markup
|
|
479
|
+
if (section, directive_line = directives['section'])
|
|
480
|
+
# If comment has :section:, it is not a documentable comment for a code object
|
|
481
|
+
comment.text = extract_section_comment(comment_text, directive_line - start_line)
|
|
482
|
+
@container.set_current_section(section, comment)
|
|
483
|
+
return
|
|
484
|
+
end
|
|
485
|
+
@preprocess.run_post_processes(comment, @container)
|
|
486
|
+
[comment, directives, type_signature_lines]
|
|
670
487
|
end
|
|
671
488
|
|
|
672
|
-
|
|
673
|
-
#
|
|
489
|
+
# Extracts the comment for this section from the normalized comment block.
|
|
490
|
+
# Removes all lines before the line that contains :section:
|
|
491
|
+
# If the comment also ends with the same content, remove it as well
|
|
674
492
|
|
|
675
|
-
def
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
493
|
+
def extract_section_comment(comment_text, prefix_line_count) # :nodoc:
|
|
494
|
+
prefix = comment_text.lines[0...prefix_line_count].join
|
|
495
|
+
comment_text.delete_prefix!(prefix)
|
|
496
|
+
# Comment is already normalized and doesn't end with a newline
|
|
497
|
+
comment_text.delete_suffix!(prefix.chomp)
|
|
498
|
+
comment_text
|
|
680
499
|
end
|
|
681
500
|
|
|
682
|
-
|
|
683
|
-
# Creates an RDoc::Attr for the name following +tk+, setting the comment to
|
|
684
|
-
# +comment+.
|
|
501
|
+
# Returns syntax highlighted tokens of the given node
|
|
685
502
|
|
|
686
|
-
def
|
|
687
|
-
|
|
503
|
+
def syntax_highlighted_tokens(node)
|
|
504
|
+
RDoc::Parser::RubyColorizer.partial_colorize(@content, node, @prism_tokens)
|
|
505
|
+
end
|
|
688
506
|
|
|
689
|
-
|
|
690
|
-
if args.size > 0 then
|
|
691
|
-
name = args[0]
|
|
692
|
-
rw = "R"
|
|
693
|
-
skip_tkspace_without_nl
|
|
694
|
-
tk = get_tk
|
|
507
|
+
# Handles `public :foo, :bar` `private :foo, :bar` and `protected :foo, :bar`
|
|
695
508
|
|
|
696
|
-
|
|
697
|
-
|
|
509
|
+
def change_method_visibility(names, visibility, singleton: @singleton)
|
|
510
|
+
new_methods = []
|
|
511
|
+
@container.methods_matching(names, singleton) do |m|
|
|
512
|
+
if m.parent != @container
|
|
513
|
+
m = m.dup
|
|
514
|
+
record_location(m)
|
|
515
|
+
new_methods << m
|
|
698
516
|
else
|
|
699
|
-
|
|
517
|
+
m.visibility = visibility
|
|
700
518
|
end
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
519
|
+
end
|
|
520
|
+
new_methods.each do |method|
|
|
521
|
+
case method
|
|
522
|
+
when RDoc::AnyMethod then
|
|
523
|
+
@container.add_method(method)
|
|
524
|
+
when RDoc::Attr then
|
|
525
|
+
@container.add_attribute(method)
|
|
526
|
+
end
|
|
527
|
+
method.visibility = visibility
|
|
708
528
|
end
|
|
709
529
|
end
|
|
710
530
|
|
|
711
|
-
|
|
712
|
-
# Creates an RDoc::Attr for each attribute listed after +tk+, setting the
|
|
713
|
-
# comment for each to +comment+.
|
|
714
|
-
|
|
715
|
-
def parse_attr_accessor(context, single, tk, comment)
|
|
716
|
-
line_no = tk[:line_no]
|
|
531
|
+
# Handles `module_function :foo, :bar`
|
|
717
532
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
case tk[:text]
|
|
728
|
-
when "attr_reader" then rw = "R"
|
|
729
|
-
when "attr_writer" then rw = "W"
|
|
730
|
-
when "attr_accessor" then rw = "RW"
|
|
731
|
-
else
|
|
732
|
-
rw = '?'
|
|
533
|
+
def change_method_to_module_function(names)
|
|
534
|
+
@container.set_visibility_for(names, :private, false)
|
|
535
|
+
new_methods = []
|
|
536
|
+
@container.methods_matching(names) do |m|
|
|
537
|
+
s_m = m.dup
|
|
538
|
+
record_location(s_m)
|
|
539
|
+
s_m.singleton = true
|
|
540
|
+
new_methods << s_m
|
|
733
541
|
end
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
542
|
+
new_methods.each do |method|
|
|
543
|
+
case method
|
|
544
|
+
when RDoc::AnyMethod then
|
|
545
|
+
@container.add_method(method)
|
|
546
|
+
when RDoc::Attr then
|
|
547
|
+
@container.add_attribute(method)
|
|
548
|
+
end
|
|
549
|
+
method.visibility = :public
|
|
738
550
|
end
|
|
739
551
|
end
|
|
740
552
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
553
|
+
def handle_code_object_directives(code_object, directives) # :nodoc:
|
|
554
|
+
directives.each do |directive, (param)|
|
|
555
|
+
@preprocess.handle_directive('', directive, param, code_object)
|
|
556
|
+
end
|
|
557
|
+
end
|
|
746
558
|
|
|
747
|
-
|
|
559
|
+
# Handles `alias foo bar` and `alias_method :foo, :bar`
|
|
748
560
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
561
|
+
def add_alias_method(old_name, new_name, line_no)
|
|
562
|
+
comment, directives = consecutive_comment(line_no)
|
|
563
|
+
handle_code_object_directives(@container, directives) if directives
|
|
564
|
+
visibility = @container.find_method(old_name, @singleton)&.visibility || :public
|
|
565
|
+
a = RDoc::Alias.new(old_name, new_name, comment, singleton: @singleton)
|
|
566
|
+
handle_modifier_directive(a, line_no)
|
|
567
|
+
a.store = @store
|
|
568
|
+
a.line = line_no
|
|
569
|
+
record_location(a)
|
|
570
|
+
if should_document?(a)
|
|
571
|
+
@container.add_alias(a)
|
|
572
|
+
@container.find_method(new_name, @singleton)&.visibility = visibility
|
|
752
573
|
end
|
|
574
|
+
end
|
|
753
575
|
|
|
754
|
-
|
|
576
|
+
# Handles `attr :a, :b`, `attr_reader :a, :b`, `attr_writer :a, :b` and `attr_accessor :a, :b`
|
|
755
577
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
end
|
|
578
|
+
def add_attributes(names, rw, line_no)
|
|
579
|
+
comment, directives, type_signature_lines = consecutive_comment(line_no)
|
|
580
|
+
handle_code_object_directives(@container, directives) if directives
|
|
581
|
+
return unless @container.document_children
|
|
761
582
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
583
|
+
names.each do |symbol|
|
|
584
|
+
a = RDoc::Attr.new(symbol.to_s, rw, comment, singleton: @singleton)
|
|
585
|
+
a.store = @store
|
|
586
|
+
a.line = line_no
|
|
587
|
+
a.type_signature_lines = type_signature_lines
|
|
588
|
+
record_location(a)
|
|
589
|
+
handle_modifier_directive(a, line_no)
|
|
590
|
+
@container.add_attribute(a) if should_document?(a)
|
|
591
|
+
a.visibility = visibility # should set after adding to container
|
|
766
592
|
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Adds includes/extends. Module name is resolved to full before adding.
|
|
767
596
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
597
|
+
def add_includes_extends(names, rdoc_class, line_no) # :nodoc:
|
|
598
|
+
comment, directives = consecutive_comment(line_no)
|
|
599
|
+
handle_code_object_directives(@container, directives) if directives
|
|
600
|
+
names.each do |name|
|
|
601
|
+
resolved_name = resolve_constant_path(name)
|
|
602
|
+
ie = @container.add(rdoc_class, resolved_name || name, '')
|
|
603
|
+
ie.store = @store
|
|
604
|
+
ie.line = line_no
|
|
605
|
+
ie.comment = comment
|
|
606
|
+
record_location(ie)
|
|
607
|
+
end
|
|
608
|
+
end
|
|
772
609
|
|
|
773
|
-
|
|
774
|
-
context.add_alias al
|
|
775
|
-
@stats.add_alias al
|
|
610
|
+
# Handle `include Foo, Bar`
|
|
776
611
|
|
|
777
|
-
|
|
612
|
+
def add_includes(names, line_no) # :nodoc:
|
|
613
|
+
add_includes_extends(names, RDoc::Include, line_no)
|
|
778
614
|
end
|
|
779
615
|
|
|
780
|
-
|
|
781
|
-
# Extracts call parameters from the token stream.
|
|
782
|
-
|
|
783
|
-
def parse_call_parameters(tk)
|
|
784
|
-
end_token = case tk[:kind]
|
|
785
|
-
when :on_lparen
|
|
786
|
-
:on_rparen
|
|
787
|
-
when :on_rparen
|
|
788
|
-
return ""
|
|
789
|
-
else
|
|
790
|
-
:on_nl
|
|
791
|
-
end
|
|
792
|
-
nest = 0
|
|
793
|
-
|
|
794
|
-
loop do
|
|
795
|
-
break if tk.nil?
|
|
796
|
-
case tk[:kind]
|
|
797
|
-
when :on_semicolon
|
|
798
|
-
break
|
|
799
|
-
when :on_lparen
|
|
800
|
-
nest += 1
|
|
801
|
-
when end_token
|
|
802
|
-
if end_token == :on_rparen
|
|
803
|
-
nest -= 1
|
|
804
|
-
break if RDoc::Parser::RipperStateLex.end?(tk) and nest <= 0
|
|
805
|
-
else
|
|
806
|
-
break if RDoc::Parser::RipperStateLex.end?(tk)
|
|
807
|
-
end
|
|
808
|
-
when :on_comment, :on_embdoc
|
|
809
|
-
unget_tk(tk)
|
|
810
|
-
break
|
|
811
|
-
when :on_op
|
|
812
|
-
if tk[:text] =~ /^(.{1,2})?=$/
|
|
813
|
-
unget_tk(tk)
|
|
814
|
-
break
|
|
815
|
-
end
|
|
816
|
-
end
|
|
817
|
-
tk = get_tk
|
|
818
|
-
end
|
|
616
|
+
# Handle `extend Foo, Bar`
|
|
819
617
|
|
|
820
|
-
|
|
618
|
+
def add_extends(names, line_no) # :nodoc:
|
|
619
|
+
add_includes_extends(names, RDoc::Extend, line_no)
|
|
821
620
|
end
|
|
822
621
|
|
|
823
|
-
|
|
824
|
-
# Parses a class in +context+ with +comment+
|
|
622
|
+
# Adds a method defined by `def` syntax
|
|
825
623
|
|
|
826
|
-
def
|
|
827
|
-
|
|
624
|
+
def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:, start_line:, args_end_line:, end_line:)
|
|
625
|
+
receiver = receiver_name ? find_or_create_lexical_module_path(receiver_name, receiver_fallback_type) : @container
|
|
626
|
+
comment, directives, type_signature_lines = consecutive_comment(start_line)
|
|
627
|
+
handle_code_object_directives(@container, directives) if directives
|
|
828
628
|
|
|
829
|
-
|
|
830
|
-
|
|
629
|
+
internal_add_method(
|
|
630
|
+
method_name,
|
|
631
|
+
receiver,
|
|
632
|
+
comment: comment,
|
|
633
|
+
directives: directives,
|
|
634
|
+
modifier_comment_lines: [start_line, args_end_line, end_line].uniq,
|
|
635
|
+
line_no: start_line,
|
|
636
|
+
visibility: visibility,
|
|
637
|
+
singleton: singleton,
|
|
638
|
+
params: params,
|
|
639
|
+
calls_super: calls_super,
|
|
640
|
+
block_params: block_params,
|
|
641
|
+
tokens: tokens,
|
|
642
|
+
type_signature_lines: type_signature_lines
|
|
643
|
+
)
|
|
644
|
+
end
|
|
831
645
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
646
|
+
private def internal_add_method(method_name, container, comment:, dont_rename_initialize: false, directives:, modifier_comment_lines: nil, line_no:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:, type_signature_lines: nil) # :nodoc:
|
|
647
|
+
meth = RDoc::AnyMethod.new(method_name, singleton: singleton)
|
|
648
|
+
meth.comment = comment
|
|
649
|
+
handle_code_object_directives(meth, directives) if directives
|
|
650
|
+
modifier_comment_lines&.each do |line|
|
|
651
|
+
handle_modifier_directive(meth, line)
|
|
652
|
+
end
|
|
653
|
+
return unless should_document?(meth)
|
|
654
|
+
|
|
655
|
+
if directives && (call_seq, = directives['call-seq'])
|
|
656
|
+
meth.call_seq = call_seq.lines.map(&:chomp).reject(&:empty?).join("\n") if call_seq
|
|
657
|
+
end
|
|
658
|
+
meth.name ||= meth.call_seq[/\A[^()\s]+/] if meth.call_seq
|
|
659
|
+
meth.name ||= 'unknown'
|
|
660
|
+
meth.store = @store
|
|
661
|
+
meth.line = line_no
|
|
662
|
+
container.add_method(meth) # should add after setting singleton and before setting visibility
|
|
663
|
+
meth.visibility = visibility
|
|
664
|
+
meth.params ||= params || '()'
|
|
665
|
+
meth.calls_super = calls_super
|
|
666
|
+
meth.block_params ||= block_params if block_params
|
|
667
|
+
meth.type_signature_lines = type_signature_lines
|
|
668
|
+
record_location(meth)
|
|
669
|
+
meth.start_collecting_tokens(:ruby)
|
|
670
|
+
tokens.each do |token|
|
|
671
|
+
meth.token_stream << token
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
# Rename after add_method to register duplicated 'new' and 'initialize'
|
|
675
|
+
# defined in c and ruby.
|
|
676
|
+
if !dont_rename_initialize && method_name == 'initialize' && !singleton
|
|
677
|
+
if meth.dont_rename_initialize
|
|
678
|
+
meth.visibility = :protected
|
|
841
679
|
else
|
|
842
|
-
|
|
680
|
+
meth.name = 'new'
|
|
681
|
+
meth.singleton = true
|
|
682
|
+
meth.visibility = :public
|
|
843
683
|
end
|
|
844
|
-
else
|
|
845
|
-
warn "Expected class name or '<<'. Got #{name_t[:kind]}: #{name_t[:text].inspect}"
|
|
846
|
-
return
|
|
847
684
|
end
|
|
685
|
+
end
|
|
848
686
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
|
|
687
|
+
# Find or create module or class from a given module name using Ruby lexical
|
|
688
|
+
# nesting. If module or class does not exist, creates a module or a class
|
|
689
|
+
# according to `create_mode` argument.
|
|
853
690
|
|
|
854
|
-
|
|
691
|
+
def find_or_create_lexical_module_path(module_name, create_mode)
|
|
692
|
+
root_name, *path, name = module_name.split('::')
|
|
693
|
+
add_module = ->(mod, name, mode) {
|
|
694
|
+
case mode
|
|
695
|
+
when :class
|
|
696
|
+
mod.add_class(RDoc::NormalClass, name, 'Object').tap { |m| m.store = @store }
|
|
697
|
+
when :module
|
|
698
|
+
mod.add_module(RDoc::NormalModule, name).tap { |m| m.store = @store }
|
|
699
|
+
end
|
|
700
|
+
}
|
|
701
|
+
if root_name.empty?
|
|
702
|
+
mod = @top_level
|
|
703
|
+
else
|
|
704
|
+
@module_nesting.reverse_each do |nesting, singleton|
|
|
705
|
+
next if singleton
|
|
706
|
+
mod = nesting.get_module_named(root_name)
|
|
707
|
+
break if mod
|
|
708
|
+
# If a constant is found and it is not a module or class, RDoc can't document about it.
|
|
709
|
+
# Return an anonymous module to avoid wrong document creation.
|
|
710
|
+
return RDoc::NormalModule.new(nil) if nesting.find_constant_named(root_name)
|
|
711
|
+
end
|
|
712
|
+
last_nesting, = @module_nesting.reverse_each.find { |_, singleton| !singleton }
|
|
713
|
+
return mod || add_module.call(last_nesting, root_name, create_mode) unless name
|
|
714
|
+
mod ||= add_module.call(last_nesting, root_name, :module)
|
|
715
|
+
end
|
|
716
|
+
path.each do |name|
|
|
717
|
+
mod = mod.get_module_named(name) || add_module.call(mod, name, :module)
|
|
718
|
+
end
|
|
719
|
+
mod.get_module_named(name) || add_module.call(mod, name, create_mode)
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
# Resolves constant path to a full path by searching module nesting
|
|
723
|
+
|
|
724
|
+
def resolve_constant_path(constant_path)
|
|
725
|
+
owner_name, path = constant_path.split('::', 2)
|
|
726
|
+
return constant_path if owner_name.empty? # ::Foo, ::Foo::Bar
|
|
727
|
+
mod = nil
|
|
728
|
+
@module_nesting.reverse_each do |nesting, singleton|
|
|
729
|
+
next if singleton
|
|
730
|
+
mod = nesting.get_module_named(owner_name)
|
|
731
|
+
break if mod
|
|
732
|
+
end
|
|
733
|
+
mod ||= @top_level.get_module_named(owner_name)
|
|
734
|
+
[mod.full_name, path].compact.join('::') if mod
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
# Returns a pair of owner module and constant name from a given constant path
|
|
738
|
+
# using Ruby lexical nesting. Creates owner module if it does not exist.
|
|
739
|
+
|
|
740
|
+
def find_or_create_lexical_constant_owner_name(constant_path)
|
|
741
|
+
const_path, colon, name = constant_path.rpartition('::')
|
|
742
|
+
if colon.empty? # class Foo
|
|
743
|
+
# Within `class C` or `module C`, owner is C(== current container)
|
|
744
|
+
# Within `class <<C`, owner is C.singleton_class
|
|
745
|
+
# but RDoc don't track constants of a singleton class of module
|
|
746
|
+
[(@singleton ? nil : @container), name]
|
|
747
|
+
elsif const_path.empty? # class ::Foo
|
|
748
|
+
[@top_level, name]
|
|
749
|
+
else # `class Foo::Bar` or `class ::Foo::Bar`
|
|
750
|
+
[find_or_create_lexical_module_path(const_path, :module), name]
|
|
751
|
+
end
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
# Adds a constant
|
|
755
|
+
|
|
756
|
+
def add_constant(constant_name, rhs_name, start_line, end_line, alias_path: nil)
|
|
757
|
+
comment, directives = consecutive_comment(start_line)
|
|
758
|
+
handle_code_object_directives(@container, directives) if directives
|
|
759
|
+
owner, name = find_or_create_lexical_constant_owner_name(constant_name)
|
|
760
|
+
return unless owner
|
|
761
|
+
|
|
762
|
+
constant = RDoc::Constant.new(name, rhs_name, comment)
|
|
763
|
+
constant.store = @store
|
|
764
|
+
constant.line = start_line
|
|
765
|
+
constant.is_alias_for_path = alias_path
|
|
766
|
+
record_location(constant)
|
|
767
|
+
handle_modifier_directive(constant, start_line)
|
|
768
|
+
handle_modifier_directive(constant, end_line)
|
|
769
|
+
owner.add_constant(constant)
|
|
770
|
+
return unless alias_path
|
|
771
|
+
mod =
|
|
772
|
+
if alias_path.start_with?('::')
|
|
773
|
+
@store.find_class_or_module(alias_path)
|
|
774
|
+
else
|
|
775
|
+
full_name = resolve_constant_path(alias_path)
|
|
776
|
+
@store.find_class_or_module(full_name)
|
|
777
|
+
end
|
|
778
|
+
if mod && constant.document_self
|
|
779
|
+
a = owner.add_module_alias(mod, alias_path, constant, @top_level)
|
|
780
|
+
a.store = @store
|
|
781
|
+
a.line = start_line
|
|
782
|
+
record_location(a)
|
|
783
|
+
end
|
|
855
784
|
end
|
|
856
785
|
|
|
857
|
-
|
|
858
|
-
# Parses and creates a regular class
|
|
786
|
+
# Adds module or class
|
|
859
787
|
|
|
860
|
-
def
|
|
861
|
-
|
|
862
|
-
|
|
788
|
+
def add_module_or_class(module_name, start_line, end_line, is_class: false, superclass_name: nil, superclass_expr: nil)
|
|
789
|
+
comment, directives = consecutive_comment(start_line)
|
|
790
|
+
handle_code_object_directives(@container, directives) if directives
|
|
791
|
+
return unless @container.document_children
|
|
863
792
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
given_name = $'
|
|
867
|
-
end
|
|
793
|
+
owner, name = find_or_create_lexical_constant_owner_name(module_name)
|
|
794
|
+
return unless owner
|
|
868
795
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
796
|
+
if is_class
|
|
797
|
+
# RDoc::NormalClass resolves superclass name despite of the lack of module nesting information.
|
|
798
|
+
# We need to fix it when RDoc::NormalClass resolved to a wrong constant name
|
|
799
|
+
if superclass_name
|
|
800
|
+
superclass_full_path = resolve_constant_path(superclass_name)
|
|
801
|
+
superclass = @store.find_class_or_module(superclass_full_path) if superclass_full_path
|
|
802
|
+
superclass_full_path ||= superclass_name
|
|
803
|
+
superclass_full_path = superclass_full_path.sub(/^::/, '')
|
|
804
|
+
end
|
|
805
|
+
# add_class should be done after resolving superclass
|
|
806
|
+
mod = owner.classes_hash[name] || owner.add_class(RDoc::NormalClass, name, superclass_name || superclass_expr || '::Object')
|
|
807
|
+
if superclass_name
|
|
808
|
+
if superclass
|
|
809
|
+
mod.superclass = superclass
|
|
810
|
+
elsif (mod.superclass.is_a?(String) || mod.superclass.name == 'Object') && mod.superclass != superclass_full_path
|
|
811
|
+
mod.superclass = superclass_full_path
|
|
812
|
+
end
|
|
813
|
+
end
|
|
814
|
+
else
|
|
815
|
+
mod = owner.modules_hash[name] || owner.add_module(RDoc::NormalModule, name)
|
|
875
816
|
end
|
|
876
817
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
818
|
+
mod.store = @store
|
|
819
|
+
mod.line = start_line
|
|
820
|
+
record_location(mod)
|
|
821
|
+
handle_modifier_directive(mod, start_line)
|
|
822
|
+
handle_modifier_directive(mod, end_line)
|
|
823
|
+
mod.add_comment(comment, @top_level) if comment
|
|
824
|
+
mod
|
|
825
|
+
end
|
|
880
826
|
|
|
881
|
-
|
|
882
|
-
record_location cls
|
|
827
|
+
private
|
|
883
828
|
|
|
884
|
-
|
|
829
|
+
# Extracts RBS type signature lines (#: ...) from raw comment text.
|
|
830
|
+
# Mutates the input text to remove the extracted lines.
|
|
831
|
+
# Returns an array of extracted type signature lines, or nil if none are
|
|
832
|
+
# found. The array may contain multiple lines for overloaded signatures.
|
|
885
833
|
|
|
886
|
-
|
|
887
|
-
|
|
834
|
+
def extract_type_signature!(text, start_line)
|
|
835
|
+
return nil unless text.include?('#:')
|
|
888
836
|
|
|
889
|
-
|
|
837
|
+
lines = text.lines
|
|
838
|
+
sig_lines, doc_lines = lines.partition { |l| l.match?(RBS_SIG_LINE) }
|
|
839
|
+
return nil if sig_lines.empty?
|
|
890
840
|
|
|
891
|
-
|
|
841
|
+
first_sig_line = start_line + lines.index(sig_lines.first)
|
|
842
|
+
text.replace(doc_lines.join)
|
|
843
|
+
type_signature_lines = sig_lines.map { |l| l.sub(RBS_SIG_LINE, '').strip }.reject(&:empty?)
|
|
844
|
+
return nil if type_signature_lines.empty?
|
|
892
845
|
|
|
893
|
-
|
|
846
|
+
warn_invalid_type_signature(type_signature_lines, first_sig_line)
|
|
847
|
+
type_signature_lines
|
|
894
848
|
end
|
|
895
849
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
850
|
+
def warn_invalid_type_signature(type_signature_lines, line_no)
|
|
851
|
+
type_signature_lines.each_with_index do |line, i|
|
|
852
|
+
next if RDoc::RbsHelper.valid_method_type?(line)
|
|
853
|
+
next if RDoc::RbsHelper.valid_type?(line)
|
|
854
|
+
@options.warn "#{@top_level.relative_name}:#{line_no + i}: invalid RBS type signature: #{line.inspect}"
|
|
855
|
+
end
|
|
856
|
+
end
|
|
899
857
|
|
|
900
|
-
|
|
901
|
-
|
|
858
|
+
class RDocVisitor < Prism::Visitor # :nodoc:
|
|
859
|
+
def initialize(scanner, top_level, store)
|
|
860
|
+
@scanner = scanner
|
|
861
|
+
@top_level = top_level
|
|
862
|
+
@store = store
|
|
863
|
+
end
|
|
902
864
|
|
|
903
|
-
|
|
904
|
-
if
|
|
905
|
-
|
|
906
|
-
|
|
865
|
+
def visit_if_node(node)
|
|
866
|
+
if node.end_keyword
|
|
867
|
+
super
|
|
868
|
+
else
|
|
869
|
+
# Visit with the order in text representation to handle this method comment
|
|
870
|
+
# # comment
|
|
871
|
+
# def f
|
|
872
|
+
# end if call_node
|
|
873
|
+
node.statements.accept(self)
|
|
874
|
+
node.predicate.accept(self)
|
|
907
875
|
end
|
|
908
|
-
|
|
909
|
-
other = container.add_module RDoc::NormalModule, name
|
|
910
|
-
record_location other
|
|
911
|
-
|
|
912
|
-
# class << $gvar
|
|
913
|
-
other.ignore if name.empty?
|
|
914
|
-
|
|
915
|
-
other.add_comment comment, @top_level
|
|
916
876
|
end
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
877
|
+
alias visit_unless_node visit_if_node
|
|
878
|
+
|
|
879
|
+
def visit_call_node(node)
|
|
880
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
881
|
+
if node.receiver.nil?
|
|
882
|
+
case node.name
|
|
883
|
+
when :attr
|
|
884
|
+
_visit_call_attr_reader_writer_accessor(node, 'R')
|
|
885
|
+
when :attr_reader
|
|
886
|
+
_visit_call_attr_reader_writer_accessor(node, 'R')
|
|
887
|
+
when :attr_writer
|
|
888
|
+
_visit_call_attr_reader_writer_accessor(node, 'W')
|
|
889
|
+
when :attr_accessor
|
|
890
|
+
_visit_call_attr_reader_writer_accessor(node, 'RW')
|
|
891
|
+
when :include
|
|
892
|
+
_visit_call_include(node)
|
|
893
|
+
when :extend
|
|
894
|
+
_visit_call_extend(node)
|
|
895
|
+
when :public
|
|
896
|
+
super
|
|
897
|
+
_visit_call_public_private_protected(node, :public)
|
|
898
|
+
when :private
|
|
899
|
+
super
|
|
900
|
+
_visit_call_public_private_protected(node, :private)
|
|
901
|
+
when :protected
|
|
902
|
+
super
|
|
903
|
+
_visit_call_public_private_protected(node, :protected)
|
|
904
|
+
when :private_constant
|
|
905
|
+
_visit_call_private_constant(node)
|
|
906
|
+
when :public_constant
|
|
907
|
+
_visit_call_public_constant(node)
|
|
908
|
+
when :require
|
|
909
|
+
_visit_call_require(node)
|
|
910
|
+
when :alias_method
|
|
911
|
+
_visit_call_alias_method(node)
|
|
912
|
+
when :module_function
|
|
913
|
+
super
|
|
914
|
+
_visit_call_module_function(node)
|
|
915
|
+
when :public_class_method
|
|
916
|
+
super
|
|
917
|
+
_visit_call_public_private_class_method(node, :public)
|
|
918
|
+
when :private_class_method
|
|
919
|
+
super
|
|
920
|
+
_visit_call_public_private_class_method(node, :private)
|
|
921
|
+
else
|
|
922
|
+
super
|
|
923
|
+
end
|
|
924
|
+
else
|
|
925
|
+
super
|
|
926
|
+
end
|
|
924
927
|
end
|
|
925
928
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
end
|
|
934
|
-
|
|
935
|
-
##
|
|
936
|
-
# Parses a constant in +context+ with +comment+. If +ignore_constants+ is
|
|
937
|
-
# true, no found constants will be added to RDoc.
|
|
938
|
-
|
|
939
|
-
def parse_constant container, tk, comment, ignore_constants = false
|
|
940
|
-
line_no = tk[:line_no]
|
|
941
|
-
|
|
942
|
-
name = tk[:text]
|
|
943
|
-
skip_tkspace_without_nl
|
|
944
|
-
|
|
945
|
-
return unless name =~ /^\w+$/
|
|
946
|
-
|
|
947
|
-
new_modules = []
|
|
948
|
-
if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then
|
|
949
|
-
unget_tk tk
|
|
950
|
-
|
|
951
|
-
container, name_t, _, new_modules = get_class_or_module container, true
|
|
929
|
+
def visit_block_node(node)
|
|
930
|
+
@scanner.with_in_proc_block do
|
|
931
|
+
# include, extend and method definition inside block are not documentable.
|
|
932
|
+
# visibility methods and attribute definition methods should be ignored inside block.
|
|
933
|
+
super
|
|
934
|
+
end
|
|
935
|
+
end
|
|
952
936
|
|
|
953
|
-
|
|
937
|
+
def visit_alias_method_node(node)
|
|
938
|
+
return if @scanner.in_proc_block
|
|
939
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
940
|
+
return unless node.old_name.is_a?(Prism::SymbolNode) && node.new_name.is_a?(Prism::SymbolNode)
|
|
941
|
+
@scanner.add_alias_method(node.old_name.value.to_s, node.new_name.value.to_s, node.location.start_line)
|
|
954
942
|
end
|
|
955
943
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
nest -= 1
|
|
966
|
-
break if nest == 0
|
|
944
|
+
def visit_module_node(node)
|
|
945
|
+
node.constant_path.accept(self)
|
|
946
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
947
|
+
module_name = constant_path_string(node.constant_path)
|
|
948
|
+
mod = @scanner.add_module_or_class(module_name, node.location.start_line, node.location.end_line) if module_name
|
|
949
|
+
if mod
|
|
950
|
+
@scanner.with_container(mod) do
|
|
951
|
+
node.body&.accept(self)
|
|
952
|
+
@scanner.process_comments_until(node.location.end_line)
|
|
967
953
|
end
|
|
954
|
+
else
|
|
955
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
968
956
|
end
|
|
969
|
-
skip_tkspace_without_nl
|
|
970
|
-
is_array_or_hash = true
|
|
971
|
-
end
|
|
972
|
-
|
|
973
|
-
unless peek_tk && :on_op == peek_tk[:kind] && '=' == peek_tk[:text] then
|
|
974
|
-
return false
|
|
975
957
|
end
|
|
976
|
-
get_tk
|
|
977
958
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
959
|
+
def visit_class_node(node)
|
|
960
|
+
node.constant_path.accept(self)
|
|
961
|
+
node.superclass&.accept(self)
|
|
962
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
963
|
+
superclass_name = constant_path_string(node.superclass) if node.superclass
|
|
964
|
+
superclass_expr = node.superclass.slice if node.superclass && !superclass_name
|
|
965
|
+
class_name = constant_path_string(node.constant_path)
|
|
966
|
+
klass = @scanner.add_module_or_class(class_name, node.location.start_line, node.location.end_line, is_class: true, superclass_name: superclass_name, superclass_expr: superclass_expr) if class_name
|
|
967
|
+
if klass
|
|
968
|
+
@scanner.with_container(klass) do
|
|
969
|
+
node.body&.accept(self)
|
|
970
|
+
@scanner.process_comments_until(node.location.end_line)
|
|
971
|
+
end
|
|
972
|
+
else
|
|
973
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
983
974
|
end
|
|
984
975
|
end
|
|
985
976
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
body = parse_constant_body container, con, is_array_or_hash
|
|
977
|
+
def visit_singleton_class_node(node)
|
|
978
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
990
979
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
|
|
997
|
-
|
|
998
|
-
return if is_array_or_hash
|
|
980
|
+
if @scanner.has_modifier_nodoc?(node.location.start_line)
|
|
981
|
+
# Skip visiting inside the singleton class. Also skips creation of node.expression as a module
|
|
982
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
983
|
+
return
|
|
984
|
+
end
|
|
999
985
|
|
|
1000
|
-
|
|
1001
|
-
|
|
986
|
+
expression = node.expression
|
|
987
|
+
expression = expression.body.body.first if expression.is_a?(Prism::ParenthesesNode) && expression.body&.body&.size == 1
|
|
988
|
+
|
|
989
|
+
case expression
|
|
990
|
+
when Prism::ConstantWriteNode
|
|
991
|
+
# Accept `class << (NameErrorCheckers = Object.new)` as a module which is not actually a module
|
|
992
|
+
mod = @scanner.container.add_module(RDoc::NormalModule, expression.name.to_s)
|
|
993
|
+
when Prism::ConstantPathNode, Prism::ConstantReadNode
|
|
994
|
+
expression_name = constant_path_string(expression)
|
|
995
|
+
# If a constant_path does not exist, RDoc creates a module
|
|
996
|
+
mod = @scanner.find_or_create_lexical_module_path(expression_name, :module) if expression_name
|
|
997
|
+
when Prism::SelfNode
|
|
998
|
+
mod = @scanner.container if @scanner.container != @top_level
|
|
999
|
+
end
|
|
1000
|
+
expression.accept(self)
|
|
1001
|
+
if mod
|
|
1002
|
+
@scanner.with_container(mod, singleton: true) do
|
|
1003
|
+
node.body&.accept(self)
|
|
1004
|
+
@scanner.process_comments_until(node.location.end_line)
|
|
1005
|
+
end
|
|
1006
|
+
else
|
|
1007
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
1008
|
+
end
|
|
1009
|
+
end
|
|
1002
1010
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1011
|
+
def visit_def_node(node)
|
|
1012
|
+
start_line = node.location.start_line
|
|
1013
|
+
args_end_line = node.parameters&.location&.end_line || start_line
|
|
1014
|
+
end_line = node.location.end_line
|
|
1015
|
+
@scanner.process_comments_until(start_line - 1)
|
|
1016
|
+
|
|
1017
|
+
return if @scanner.in_proc_block
|
|
1018
|
+
|
|
1019
|
+
case node.receiver
|
|
1020
|
+
when Prism::NilNode, Prism::TrueNode, Prism::FalseNode
|
|
1021
|
+
visibility = :public
|
|
1022
|
+
singleton = false
|
|
1023
|
+
receiver_name =
|
|
1024
|
+
case node.receiver
|
|
1025
|
+
when Prism::NilNode
|
|
1026
|
+
'NilClass'
|
|
1027
|
+
when Prism::TrueNode
|
|
1028
|
+
'TrueClass'
|
|
1029
|
+
when Prism::FalseNode
|
|
1030
|
+
'FalseClass'
|
|
1031
|
+
end
|
|
1032
|
+
receiver_fallback_type = :class
|
|
1033
|
+
when Prism::SelfNode
|
|
1034
|
+
# singleton method of a singleton class is not documentable
|
|
1035
|
+
return if @scanner.singleton
|
|
1036
|
+
visibility = :public
|
|
1037
|
+
singleton = true
|
|
1038
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
|
1039
|
+
visibility = :public
|
|
1040
|
+
singleton = true
|
|
1041
|
+
receiver_name = constant_path_string(node.receiver)
|
|
1042
|
+
receiver_fallback_type = :module
|
|
1043
|
+
return unless receiver_name
|
|
1044
|
+
when nil
|
|
1045
|
+
visibility = @scanner.visibility
|
|
1046
|
+
singleton = @scanner.singleton
|
|
1047
|
+
else
|
|
1048
|
+
# `def (unknown expression).method_name` is not documentable
|
|
1049
|
+
return
|
|
1050
|
+
end
|
|
1051
|
+
name = node.name.to_s
|
|
1052
|
+
params, block_params, calls_super = MethodSignatureVisitor.scan_signature(node)
|
|
1053
|
+
tokens = @scanner.syntax_highlighted_tokens(node)
|
|
1054
|
+
|
|
1055
|
+
@scanner.add_method(
|
|
1056
|
+
name,
|
|
1057
|
+
receiver_name: receiver_name,
|
|
1058
|
+
receiver_fallback_type: receiver_fallback_type,
|
|
1059
|
+
visibility: visibility,
|
|
1060
|
+
singleton: singleton,
|
|
1061
|
+
params: params,
|
|
1062
|
+
block_params: block_params,
|
|
1063
|
+
calls_super: calls_super,
|
|
1064
|
+
tokens: tokens,
|
|
1065
|
+
start_line: start_line,
|
|
1066
|
+
args_end_line: args_end_line,
|
|
1067
|
+
end_line: end_line
|
|
1068
|
+
)
|
|
1069
|
+
ensure
|
|
1070
|
+
@scanner.skip_comments_until(end_line)
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
def visit_constant_path_write_node(node)
|
|
1074
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
1075
|
+
path = constant_path_string(node.target)
|
|
1076
|
+
return unless path
|
|
1077
|
+
|
|
1078
|
+
alias_path = constant_path_string(node.value)
|
|
1079
|
+
@scanner.add_constant(
|
|
1080
|
+
path,
|
|
1081
|
+
alias_path || node.value.slice,
|
|
1082
|
+
node.location.start_line,
|
|
1083
|
+
node.location.end_line,
|
|
1084
|
+
alias_path: alias_path
|
|
1085
|
+
)
|
|
1086
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
1087
|
+
# Do not traverse rhs not to document `A::B = Struct.new{def undocumentable_method; end}`
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
def visit_constant_write_node(node)
|
|
1091
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
1092
|
+
alias_path = constant_path_string(node.value)
|
|
1093
|
+
@scanner.add_constant(
|
|
1094
|
+
node.name.to_s,
|
|
1095
|
+
alias_path || node.value.slice,
|
|
1096
|
+
node.location.start_line,
|
|
1097
|
+
node.location.end_line,
|
|
1098
|
+
alias_path: alias_path
|
|
1099
|
+
)
|
|
1100
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
1101
|
+
# Do not traverse rhs not to document `A = Struct.new{def undocumentable_method; end}`
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
private
|
|
1105
|
+
|
|
1106
|
+
def constant_arguments_names(call_node)
|
|
1107
|
+
return unless call_node.arguments
|
|
1108
|
+
names = call_node.arguments.arguments.map { |arg| constant_path_string(arg) }
|
|
1109
|
+
names.all? ? names : nil
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
def symbol_arguments(call_node)
|
|
1113
|
+
arguments_node = call_node.arguments
|
|
1114
|
+
return unless arguments_node && arguments_node.arguments.all? { |arg| arg.is_a?(Prism::SymbolNode)}
|
|
1115
|
+
arguments_node.arguments.map { |arg| arg.value.to_sym }
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
def visibility_method_arguments(call_node, singleton:)
|
|
1119
|
+
arguments_node = call_node.arguments
|
|
1120
|
+
return unless arguments_node
|
|
1121
|
+
symbols = symbol_arguments(call_node)
|
|
1122
|
+
if symbols
|
|
1123
|
+
# module_function :foo, :bar
|
|
1124
|
+
return symbols.map(&:to_s)
|
|
1125
|
+
else
|
|
1126
|
+
return unless arguments_node.arguments.size == 1
|
|
1127
|
+
arg = arguments_node.arguments.first
|
|
1128
|
+
return unless arg.is_a?(Prism::DefNode)
|
|
1005
1129
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
get_tkread
|
|
1011
|
-
|
|
1012
|
-
tk = get_tk
|
|
1013
|
-
|
|
1014
|
-
body = nil
|
|
1015
|
-
loop do
|
|
1016
|
-
break if tk.nil?
|
|
1017
|
-
if :on_semicolon == tk[:kind] then
|
|
1018
|
-
break if nest <= 0
|
|
1019
|
-
elsif [:on_tlambeg, :on_lparen, :on_lbrace, :on_lbracket].include?(tk[:kind]) then
|
|
1020
|
-
nest += 1
|
|
1021
|
-
elsif (:on_kw == tk[:kind] && 'def' == tk[:text]) then
|
|
1022
|
-
nest += 1
|
|
1023
|
-
elsif (:on_kw == tk[:kind] && %w{do if unless case begin}.include?(tk[:text])) then
|
|
1024
|
-
if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
|
|
1025
|
-
nest += 1
|
|
1026
|
-
end
|
|
1027
|
-
elsif [:on_rparen, :on_rbrace, :on_rbracket].include?(tk[:kind]) ||
|
|
1028
|
-
(:on_kw == tk[:kind] && 'end' == tk[:text]) then
|
|
1029
|
-
nest -= 1
|
|
1030
|
-
elsif (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then
|
|
1031
|
-
unget_tk tk
|
|
1032
|
-
if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then
|
|
1033
|
-
body = get_tkread_clean(/^[ \t]+/, '')
|
|
1034
|
-
read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS
|
|
1035
|
-
break
|
|
1130
|
+
if singleton
|
|
1131
|
+
# `private_class_method def foo; end` `private_class_method def not_self.foo; end` should be ignored
|
|
1132
|
+
return unless arg.receiver.is_a?(Prism::SelfNode)
|
|
1036
1133
|
else
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
elsif :on_const == tk[:kind] then
|
|
1040
|
-
rhs_name << tk[:text]
|
|
1041
|
-
|
|
1042
|
-
next_tk = peek_tk
|
|
1043
|
-
if nest <= 0 and (next_tk.nil? || :on_nl == next_tk[:kind]) then
|
|
1044
|
-
create_module_alias container, constant, rhs_name unless is_array_or_hash
|
|
1045
|
-
break
|
|
1134
|
+
# `module_function def something.foo` should be ignored
|
|
1135
|
+
return if arg.receiver
|
|
1046
1136
|
end
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
unget_tk tk
|
|
1050
|
-
break
|
|
1051
|
-
end
|
|
1052
|
-
elsif :on_op == tk[:kind] && '::' == tk[:text]
|
|
1053
|
-
rhs_name << '::'
|
|
1137
|
+
# `module_function def foo; end` or `private_class_method def self.foo; end`
|
|
1138
|
+
[arg.name.to_s]
|
|
1054
1139
|
end
|
|
1055
|
-
tk = get_tk
|
|
1056
1140
|
end
|
|
1057
1141
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1142
|
+
def constant_path_string(node)
|
|
1143
|
+
case node
|
|
1144
|
+
when Prism::ConstantReadNode
|
|
1145
|
+
node.name.to_s
|
|
1146
|
+
when Prism::ConstantPathNode
|
|
1147
|
+
parent_name = node.parent ? constant_path_string(node.parent) : ''
|
|
1148
|
+
"#{parent_name}::#{node.name}" if parent_name
|
|
1149
|
+
end
|
|
1150
|
+
end
|
|
1060
1151
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1152
|
+
def _visit_call_require(call_node)
|
|
1153
|
+
return unless call_node.arguments&.arguments&.size == 1
|
|
1154
|
+
arg = call_node.arguments.arguments.first
|
|
1155
|
+
return unless arg.is_a?(Prism::StringNode)
|
|
1156
|
+
@scanner.container.add_require(RDoc::Require.new(arg.unescaped, nil))
|
|
1157
|
+
end
|
|
1064
1158
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1159
|
+
def _visit_call_module_function(call_node)
|
|
1160
|
+
return if @scanner.in_proc_block || @scanner.singleton
|
|
1161
|
+
names = visibility_method_arguments(call_node, singleton: false)&.map(&:to_s)
|
|
1162
|
+
@scanner.change_method_to_module_function(names) if names
|
|
1163
|
+
end
|
|
1069
1164
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1165
|
+
def _visit_call_public_private_class_method(call_node, visibility)
|
|
1166
|
+
return if @scanner.in_proc_block || @scanner.singleton
|
|
1167
|
+
names = visibility_method_arguments(call_node, singleton: true)
|
|
1168
|
+
@scanner.change_method_visibility(names, visibility, singleton: true) if names
|
|
1169
|
+
end
|
|
1072
1170
|
|
|
1073
|
-
|
|
1074
|
-
if
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1171
|
+
def _visit_call_public_private_protected(call_node, visibility)
|
|
1172
|
+
return if @scanner.in_proc_block
|
|
1173
|
+
arguments_node = call_node.arguments
|
|
1174
|
+
if arguments_node.nil? # `public` `private`
|
|
1175
|
+
@scanner.visibility = visibility
|
|
1176
|
+
else # `public :foo, :bar`, `private def foo; end`
|
|
1177
|
+
names = visibility_method_arguments(call_node, singleton: false)
|
|
1178
|
+
@scanner.change_method_visibility(names, visibility) if names
|
|
1079
1179
|
end
|
|
1180
|
+
end
|
|
1080
1181
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1182
|
+
def _visit_call_alias_method(call_node)
|
|
1183
|
+
return if @scanner.in_proc_block
|
|
1184
|
+
|
|
1185
|
+
new_name, old_name, *rest = symbol_arguments(call_node)
|
|
1186
|
+
return unless old_name && new_name && rest.empty?
|
|
1187
|
+
@scanner.add_alias_method(old_name.to_s, new_name.to_s, call_node.location.start_line)
|
|
1084
1188
|
end
|
|
1085
1189
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1190
|
+
def _visit_call_include(call_node)
|
|
1191
|
+
return if @scanner.in_proc_block
|
|
1088
1192
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1193
|
+
names = constant_arguments_names(call_node)
|
|
1194
|
+
line_no = call_node.location.start_line
|
|
1195
|
+
return unless names
|
|
1092
1196
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1197
|
+
if @scanner.singleton
|
|
1198
|
+
@scanner.add_extends(names, line_no)
|
|
1199
|
+
else
|
|
1200
|
+
@scanner.add_includes(names, line_no)
|
|
1201
|
+
end
|
|
1202
|
+
end
|
|
1095
1203
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
when 'attr_writer' then 'W'
|
|
1099
|
-
else 'RW'
|
|
1100
|
-
end
|
|
1204
|
+
def _visit_call_extend(call_node)
|
|
1205
|
+
return if @scanner.in_proc_block
|
|
1101
1206
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1207
|
+
names = constant_arguments_names(call_node)
|
|
1208
|
+
@scanner.add_extends(names, call_node.location.start_line) if names && !@scanner.singleton
|
|
1209
|
+
end
|
|
1104
1210
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1211
|
+
def _visit_call_public_constant(call_node)
|
|
1212
|
+
return if @scanner.in_proc_block || @scanner.singleton
|
|
1213
|
+
names = symbol_arguments(call_node)
|
|
1214
|
+
@scanner.container.set_constant_visibility_for(names.map(&:to_s), :public) if names
|
|
1215
|
+
end
|
|
1108
1216
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1217
|
+
def _visit_call_private_constant(call_node)
|
|
1218
|
+
return if @scanner.in_proc_block || @scanner.singleton
|
|
1219
|
+
names = symbol_arguments(call_node)
|
|
1220
|
+
@scanner.container.set_constant_visibility_for(names.map(&:to_s), :private) if names
|
|
1221
|
+
end
|
|
1111
1222
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
meth.add_tokens [position_comment, newline, indent]
|
|
1223
|
+
def _visit_call_attr_reader_writer_accessor(call_node, rw)
|
|
1224
|
+
return if @scanner.in_proc_block
|
|
1225
|
+
names = symbol_arguments(call_node)
|
|
1226
|
+
@scanner.add_attributes(names.map(&:to_s), rw, call_node.location.start_line) if names
|
|
1227
|
+
end
|
|
1118
1228
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1229
|
+
class MethodSignatureVisitor < Prism::Visitor # :nodoc:
|
|
1230
|
+
class << self
|
|
1231
|
+
def scan_signature(def_node)
|
|
1232
|
+
visitor = new
|
|
1233
|
+
def_node.body&.accept(visitor)
|
|
1234
|
+
params = "(#{def_node.parameters&.slice})"
|
|
1235
|
+
block_params = visitor.yields.first
|
|
1236
|
+
[params, block_params, visitor.calls_super]
|
|
1237
|
+
end
|
|
1124
1238
|
end
|
|
1125
1239
|
|
|
1126
|
-
|
|
1127
|
-
comment.extract_call_seq meth
|
|
1240
|
+
attr_reader :params, :yields, :calls_super
|
|
1128
1241
|
|
|
1129
|
-
|
|
1242
|
+
def initialize
|
|
1243
|
+
@params = nil
|
|
1244
|
+
@calls_super = false
|
|
1245
|
+
@yields = []
|
|
1246
|
+
end
|
|
1130
1247
|
|
|
1131
|
-
|
|
1248
|
+
def visit_def_node(node)
|
|
1249
|
+
# stop traverse inside nested def
|
|
1250
|
+
end
|
|
1132
1251
|
|
|
1133
|
-
|
|
1252
|
+
def visit_yield_node(node)
|
|
1253
|
+
@yields << (node.arguments&.slice || '')
|
|
1254
|
+
end
|
|
1134
1255
|
|
|
1135
|
-
|
|
1256
|
+
def visit_super_node(node)
|
|
1257
|
+
@calls_super = true
|
|
1258
|
+
super
|
|
1259
|
+
end
|
|
1136
1260
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
##
|
|
1141
|
-
# Creates an RDoc::Method on +container+ from +comment+ if there is a
|
|
1142
|
-
# Signature section in the comment
|
|
1143
|
-
|
|
1144
|
-
def parse_comment_tomdoc container, tk, comment
|
|
1145
|
-
return unless signature = RDoc::TomDoc.signature(comment)
|
|
1146
|
-
column = tk[:char_no]
|
|
1147
|
-
line_no = tk[:line_no]
|
|
1148
|
-
|
|
1149
|
-
name, = signature.split %r%[ \(]%, 2
|
|
1150
|
-
|
|
1151
|
-
meth = RDoc::GhostMethod.new get_tkread, name
|
|
1152
|
-
record_location meth
|
|
1153
|
-
meth.line = line_no
|
|
1154
|
-
|
|
1155
|
-
meth.start_collecting_tokens
|
|
1156
|
-
indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
|
|
1157
|
-
position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
|
|
1158
|
-
position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
|
|
1159
|
-
newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
|
|
1160
|
-
meth.add_tokens [position_comment, newline, indent]
|
|
1161
|
-
|
|
1162
|
-
meth.call_seq = signature
|
|
1163
|
-
|
|
1164
|
-
comment.normalize
|
|
1165
|
-
|
|
1166
|
-
return unless meth.name
|
|
1167
|
-
|
|
1168
|
-
container.add_method meth
|
|
1169
|
-
|
|
1170
|
-
meth.comment = comment
|
|
1171
|
-
|
|
1172
|
-
@stats.add_method meth
|
|
1173
|
-
end
|
|
1174
|
-
|
|
1175
|
-
##
|
|
1176
|
-
# Parses an +include+ or +extend+, indicated by the +klass+ and adds it to
|
|
1177
|
-
# +container+ # with +comment+
|
|
1178
|
-
|
|
1179
|
-
def parse_extend_or_include klass, container, comment # :nodoc:
|
|
1180
|
-
loop do
|
|
1181
|
-
skip_tkspace_comment
|
|
1182
|
-
|
|
1183
|
-
name = get_included_module_with_optional_parens
|
|
1184
|
-
|
|
1185
|
-
unless name.empty? then
|
|
1186
|
-
obj = container.add klass, name, comment
|
|
1187
|
-
record_location obj
|
|
1188
|
-
end
|
|
1189
|
-
|
|
1190
|
-
return if peek_tk.nil? || :on_comma != peek_tk[:kind]
|
|
1191
|
-
|
|
1192
|
-
get_tk
|
|
1193
|
-
end
|
|
1194
|
-
end
|
|
1195
|
-
|
|
1196
|
-
##
|
|
1197
|
-
# Parses identifiers that can create new methods or change visibility.
|
|
1198
|
-
#
|
|
1199
|
-
# Returns true if the comment was not consumed.
|
|
1200
|
-
|
|
1201
|
-
def parse_identifier container, single, tk, comment # :nodoc:
|
|
1202
|
-
case tk[:text]
|
|
1203
|
-
when 'private', 'protected', 'public', 'private_class_method',
|
|
1204
|
-
'public_class_method', 'module_function' then
|
|
1205
|
-
parse_visibility container, single, tk
|
|
1206
|
-
return true
|
|
1207
|
-
when 'private_constant', 'public_constant'
|
|
1208
|
-
parse_constant_visibility container, single, tk
|
|
1209
|
-
return true
|
|
1210
|
-
when 'attr' then
|
|
1211
|
-
parse_attr container, single, tk, comment
|
|
1212
|
-
when /^attr_(reader|writer|accessor)$/ then
|
|
1213
|
-
parse_attr_accessor container, single, tk, comment
|
|
1214
|
-
when 'alias_method' then
|
|
1215
|
-
parse_alias container, single, tk, comment
|
|
1216
|
-
when 'require', 'include' then
|
|
1217
|
-
# ignore
|
|
1218
|
-
else
|
|
1219
|
-
if comment.text =~ /\A#\#$/ then
|
|
1220
|
-
case comment.text
|
|
1221
|
-
when /^# +:?attr(_reader|_writer|_accessor)?:/ then
|
|
1222
|
-
parse_meta_attr container, single, tk, comment
|
|
1223
|
-
else
|
|
1224
|
-
method = parse_meta_method container, single, tk, comment
|
|
1225
|
-
method.params = container.params if
|
|
1226
|
-
container.params
|
|
1227
|
-
method.block_params = container.block_params if
|
|
1228
|
-
container.block_params
|
|
1229
|
-
end
|
|
1230
|
-
end
|
|
1231
|
-
end
|
|
1232
|
-
|
|
1233
|
-
false
|
|
1234
|
-
end
|
|
1235
|
-
|
|
1236
|
-
##
|
|
1237
|
-
# Parses a meta-programmed attribute and creates an RDoc::Attr.
|
|
1238
|
-
#
|
|
1239
|
-
# To create foo and bar attributes on class C with comment "My attributes":
|
|
1240
|
-
#
|
|
1241
|
-
# class C
|
|
1242
|
-
#
|
|
1243
|
-
# ##
|
|
1244
|
-
# # :attr:
|
|
1245
|
-
# #
|
|
1246
|
-
# # My attributes
|
|
1247
|
-
#
|
|
1248
|
-
# my_attr :foo, :bar
|
|
1249
|
-
#
|
|
1250
|
-
# end
|
|
1251
|
-
#
|
|
1252
|
-
# To create a foo attribute on class C with comment "My attribute":
|
|
1253
|
-
#
|
|
1254
|
-
# class C
|
|
1255
|
-
#
|
|
1256
|
-
# ##
|
|
1257
|
-
# # :attr: foo
|
|
1258
|
-
# #
|
|
1259
|
-
# # My attribute
|
|
1260
|
-
#
|
|
1261
|
-
# my_attr :foo, :bar
|
|
1262
|
-
#
|
|
1263
|
-
# end
|
|
1264
|
-
|
|
1265
|
-
def parse_meta_attr(context, single, tk, comment)
|
|
1266
|
-
args = parse_symbol_arg
|
|
1267
|
-
rw = "?"
|
|
1268
|
-
|
|
1269
|
-
# If nodoc is given, don't document any of them
|
|
1270
|
-
|
|
1271
|
-
tmp = RDoc::CodeObject.new
|
|
1272
|
-
read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
|
|
1273
|
-
|
|
1274
|
-
regexp = /^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i
|
|
1275
|
-
if regexp =~ comment.text then
|
|
1276
|
-
comment.text = comment.text.sub(regexp, '')
|
|
1277
|
-
rw = case $1
|
|
1278
|
-
when 'attr_reader' then 'R'
|
|
1279
|
-
when 'attr_writer' then 'W'
|
|
1280
|
-
else 'RW'
|
|
1281
|
-
end
|
|
1282
|
-
name = $3 unless $3.empty?
|
|
1283
|
-
end
|
|
1284
|
-
|
|
1285
|
-
if name then
|
|
1286
|
-
att = create_attr context, single, name, rw, comment
|
|
1287
|
-
else
|
|
1288
|
-
args.each do |attr_name|
|
|
1289
|
-
att = create_attr context, single, attr_name, rw, comment
|
|
1290
|
-
end
|
|
1291
|
-
end
|
|
1292
|
-
|
|
1293
|
-
att
|
|
1294
|
-
end
|
|
1295
|
-
|
|
1296
|
-
##
|
|
1297
|
-
# Parses a meta-programmed method
|
|
1298
|
-
|
|
1299
|
-
def parse_meta_method(container, single, tk, comment)
|
|
1300
|
-
column = tk[:char_no]
|
|
1301
|
-
line_no = tk[:line_no]
|
|
1302
|
-
|
|
1303
|
-
start_collecting_tokens
|
|
1304
|
-
add_token tk
|
|
1305
|
-
add_token_listener self
|
|
1306
|
-
|
|
1307
|
-
skip_tkspace_without_nl
|
|
1308
|
-
|
|
1309
|
-
comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3')
|
|
1310
|
-
singleton = !!$~
|
|
1311
|
-
|
|
1312
|
-
name = parse_meta_method_name comment, tk
|
|
1313
|
-
|
|
1314
|
-
return unless name
|
|
1315
|
-
|
|
1316
|
-
meth = RDoc::MetaMethod.new get_tkread, name
|
|
1317
|
-
record_location meth
|
|
1318
|
-
meth.line = line_no
|
|
1319
|
-
meth.singleton = singleton
|
|
1320
|
-
|
|
1321
|
-
remove_token_listener self
|
|
1322
|
-
|
|
1323
|
-
meth.start_collecting_tokens
|
|
1324
|
-
indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
|
|
1325
|
-
position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
|
|
1326
|
-
position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
|
|
1327
|
-
newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
|
|
1328
|
-
meth.add_tokens [position_comment, newline, indent]
|
|
1329
|
-
meth.add_tokens @token_stream
|
|
1330
|
-
|
|
1331
|
-
parse_meta_method_params container, single, meth, tk, comment
|
|
1332
|
-
|
|
1333
|
-
meth.comment = comment
|
|
1334
|
-
|
|
1335
|
-
@stats.add_method meth
|
|
1336
|
-
|
|
1337
|
-
meth
|
|
1338
|
-
end
|
|
1339
|
-
|
|
1340
|
-
##
|
|
1341
|
-
# Parses the name of a metaprogrammed method. +comment+ is used to
|
|
1342
|
-
# determine the name while +tk+ is used in an error message if the name
|
|
1343
|
-
# cannot be determined.
|
|
1344
|
-
|
|
1345
|
-
def parse_meta_method_name comment, tk # :nodoc:
|
|
1346
|
-
if comment.text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
|
|
1347
|
-
return $1 unless $1.empty?
|
|
1348
|
-
end
|
|
1349
|
-
|
|
1350
|
-
name_t = get_tk
|
|
1351
|
-
|
|
1352
|
-
if :on_symbol == name_t[:kind] then
|
|
1353
|
-
name_t[:text][1..-1]
|
|
1354
|
-
elsif :on_tstring == name_t[:kind] then
|
|
1355
|
-
name_t[:text][1..-2]
|
|
1356
|
-
elsif :on_op == name_t[:kind] && '=' == name_t[:text] then # ignore
|
|
1357
|
-
remove_token_listener self
|
|
1358
|
-
|
|
1359
|
-
nil
|
|
1360
|
-
else
|
|
1361
|
-
warn "unknown name token #{name_t.inspect} for meta-method '#{tk[:text]}'"
|
|
1362
|
-
'unknown'
|
|
1363
|
-
end
|
|
1364
|
-
end
|
|
1365
|
-
|
|
1366
|
-
##
|
|
1367
|
-
# Parses the parameters and block for a meta-programmed method.
|
|
1368
|
-
|
|
1369
|
-
def parse_meta_method_params container, single, meth, tk, comment # :nodoc:
|
|
1370
|
-
token_listener meth do
|
|
1371
|
-
meth.params = ''
|
|
1372
|
-
|
|
1373
|
-
look_for_directives_in meth, comment
|
|
1374
|
-
comment.normalize
|
|
1375
|
-
comment.extract_call_seq meth
|
|
1376
|
-
|
|
1377
|
-
container.add_method meth
|
|
1378
|
-
|
|
1379
|
-
last_tk = tk
|
|
1380
|
-
|
|
1381
|
-
while tk = get_tk do
|
|
1382
|
-
if :on_semicolon == tk[:kind] then
|
|
1383
|
-
break
|
|
1384
|
-
elsif :on_nl == tk[:kind] then
|
|
1385
|
-
break unless last_tk and :on_comma == last_tk[:kind]
|
|
1386
|
-
elsif :on_sp == tk[:kind] then
|
|
1387
|
-
# expression continues
|
|
1388
|
-
elsif :on_kw == tk[:kind] && 'do' == tk[:text] then
|
|
1389
|
-
parse_statements container, single, meth
|
|
1390
|
-
break
|
|
1391
|
-
else
|
|
1392
|
-
last_tk = tk
|
|
1393
|
-
end
|
|
1394
|
-
end
|
|
1395
|
-
end
|
|
1396
|
-
end
|
|
1397
|
-
|
|
1398
|
-
##
|
|
1399
|
-
# Parses a normal method defined by +def+
|
|
1400
|
-
|
|
1401
|
-
def parse_method(container, single, tk, comment)
|
|
1402
|
-
singleton = nil
|
|
1403
|
-
added_container = false
|
|
1404
|
-
name = nil
|
|
1405
|
-
column = tk[:char_no]
|
|
1406
|
-
line_no = tk[:line_no]
|
|
1407
|
-
|
|
1408
|
-
start_collecting_tokens
|
|
1409
|
-
add_token tk
|
|
1410
|
-
|
|
1411
|
-
token_listener self do
|
|
1412
|
-
prev_container = container
|
|
1413
|
-
name, container, singleton = parse_method_name container
|
|
1414
|
-
added_container = container != prev_container
|
|
1415
|
-
end
|
|
1416
|
-
|
|
1417
|
-
return unless name
|
|
1418
|
-
|
|
1419
|
-
meth = RDoc::AnyMethod.new get_tkread, name
|
|
1420
|
-
look_for_directives_in meth, comment
|
|
1421
|
-
meth.singleton = single == SINGLE ? true : singleton
|
|
1422
|
-
|
|
1423
|
-
record_location meth
|
|
1424
|
-
meth.line = line_no
|
|
1425
|
-
|
|
1426
|
-
meth.start_collecting_tokens
|
|
1427
|
-
indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
|
|
1428
|
-
token = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
|
|
1429
|
-
token[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
|
|
1430
|
-
newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
|
|
1431
|
-
meth.add_tokens [token, newline, indent]
|
|
1432
|
-
meth.add_tokens @token_stream
|
|
1433
|
-
|
|
1434
|
-
parse_method_params_and_body container, single, meth, added_container
|
|
1435
|
-
|
|
1436
|
-
comment.normalize
|
|
1437
|
-
comment.extract_call_seq meth
|
|
1438
|
-
|
|
1439
|
-
meth.comment = comment
|
|
1440
|
-
|
|
1441
|
-
# after end modifiers
|
|
1442
|
-
read_documentation_modifiers meth, RDoc::METHOD_MODIFIERS
|
|
1443
|
-
|
|
1444
|
-
@stats.add_method meth
|
|
1445
|
-
end
|
|
1446
|
-
|
|
1447
|
-
##
|
|
1448
|
-
# Parses the parameters and body of +meth+
|
|
1449
|
-
|
|
1450
|
-
def parse_method_params_and_body container, single, meth, added_container
|
|
1451
|
-
token_listener meth do
|
|
1452
|
-
parse_method_parameters meth
|
|
1453
|
-
|
|
1454
|
-
if meth.document_self or not @track_visibility then
|
|
1455
|
-
container.add_method meth
|
|
1456
|
-
elsif added_container then
|
|
1457
|
-
container.document_self = false
|
|
1458
|
-
end
|
|
1459
|
-
|
|
1460
|
-
# Having now read the method parameters and documentation modifiers, we
|
|
1461
|
-
# now know whether we have to rename #initialize to ::new
|
|
1462
|
-
|
|
1463
|
-
if meth.name == "initialize" && !meth.singleton then
|
|
1464
|
-
if meth.dont_rename_initialize then
|
|
1465
|
-
meth.visibility = :protected
|
|
1466
|
-
else
|
|
1467
|
-
meth.singleton = true
|
|
1468
|
-
meth.name = "new"
|
|
1469
|
-
meth.visibility = :public
|
|
1470
|
-
end
|
|
1471
|
-
end
|
|
1472
|
-
|
|
1473
|
-
parse_statements container, single, meth
|
|
1474
|
-
end
|
|
1475
|
-
end
|
|
1476
|
-
|
|
1477
|
-
##
|
|
1478
|
-
# Parses a method that needs to be ignored.
|
|
1479
|
-
|
|
1480
|
-
def parse_method_dummy container
|
|
1481
|
-
dummy = RDoc::Context.new
|
|
1482
|
-
dummy.parent = container
|
|
1483
|
-
dummy.store = container.store
|
|
1484
|
-
skip_method dummy
|
|
1485
|
-
end
|
|
1486
|
-
|
|
1487
|
-
##
|
|
1488
|
-
# Parses the name of a method in +container+.
|
|
1489
|
-
#
|
|
1490
|
-
# Returns the method name, the container it is in (for def Foo.name) and if
|
|
1491
|
-
# it is a singleton or regular method.
|
|
1492
|
-
|
|
1493
|
-
def parse_method_name container # :nodoc:
|
|
1494
|
-
skip_tkspace
|
|
1495
|
-
name_t = get_tk
|
|
1496
|
-
back_tk = skip_tkspace_without_nl
|
|
1497
|
-
singleton = false
|
|
1498
|
-
|
|
1499
|
-
dot = get_tk
|
|
1500
|
-
if dot[:kind] == :on_period || (dot[:kind] == :on_op && dot[:text] == '::') then
|
|
1501
|
-
singleton = true
|
|
1502
|
-
|
|
1503
|
-
name, container = parse_method_name_singleton container, name_t
|
|
1504
|
-
else
|
|
1505
|
-
unget_tk dot
|
|
1506
|
-
back_tk.reverse_each do |token|
|
|
1507
|
-
unget_tk token
|
|
1508
|
-
end
|
|
1509
|
-
|
|
1510
|
-
name = parse_method_name_regular container, name_t
|
|
1511
|
-
end
|
|
1512
|
-
|
|
1513
|
-
return name, container, singleton
|
|
1514
|
-
end
|
|
1515
|
-
|
|
1516
|
-
##
|
|
1517
|
-
# For the given +container+ and initial name token +name_t+ the method name
|
|
1518
|
-
# is parsed from the token stream for a regular method.
|
|
1519
|
-
|
|
1520
|
-
def parse_method_name_regular container, name_t # :nodoc:
|
|
1521
|
-
if :on_op == name_t[:kind] && (%w{* & [] []= <<}.include?(name_t[:text])) then
|
|
1522
|
-
name_t[:text]
|
|
1523
|
-
else
|
|
1524
|
-
unless [:on_kw, :on_const, :on_ident].include?(name_t[:kind]) then
|
|
1525
|
-
warn "expected method name token, . or ::, got #{name_t.inspect}"
|
|
1526
|
-
skip_method container
|
|
1527
|
-
return
|
|
1528
|
-
end
|
|
1529
|
-
name_t[:text]
|
|
1530
|
-
end
|
|
1531
|
-
end
|
|
1532
|
-
|
|
1533
|
-
##
|
|
1534
|
-
# For the given +container+ and initial name token +name_t+ the method name
|
|
1535
|
-
# and the new +container+ (if necessary) are parsed from the token stream
|
|
1536
|
-
# for a singleton method.
|
|
1537
|
-
|
|
1538
|
-
def parse_method_name_singleton container, name_t # :nodoc:
|
|
1539
|
-
skip_tkspace
|
|
1540
|
-
name_t2 = get_tk
|
|
1541
|
-
|
|
1542
|
-
if (:on_kw == name_t[:kind] && 'self' == name_t[:text]) || (:on_op == name_t[:kind] && '%' == name_t[:text]) then
|
|
1543
|
-
# NOTE: work around '[' being consumed early
|
|
1544
|
-
if :on_lbracket == name_t2[:kind]
|
|
1545
|
-
get_tk
|
|
1546
|
-
name = '[]'
|
|
1547
|
-
else
|
|
1548
|
-
name = name_t2[:text]
|
|
1549
|
-
end
|
|
1550
|
-
elsif :on_const == name_t[:kind] then
|
|
1551
|
-
name = name_t2[:text]
|
|
1552
|
-
|
|
1553
|
-
container = get_method_container container, name_t
|
|
1554
|
-
|
|
1555
|
-
return unless container
|
|
1556
|
-
|
|
1557
|
-
name
|
|
1558
|
-
elsif :on_ident == name_t[:kind] || :on_ivar == name_t[:kind] || :on_gvar == name_t[:kind] then
|
|
1559
|
-
parse_method_dummy container
|
|
1560
|
-
|
|
1561
|
-
name = nil
|
|
1562
|
-
elsif (:on_kw == name_t[:kind]) && ('true' == name_t[:text] || 'false' == name_t[:text] || 'nil' == name_t[:text]) then
|
|
1563
|
-
klass_name = "#{name_t[:text].capitalize}Class"
|
|
1564
|
-
container = @store.find_class_named klass_name
|
|
1565
|
-
container ||= @top_level.add_class RDoc::NormalClass, klass_name
|
|
1566
|
-
|
|
1567
|
-
name = name_t2[:text]
|
|
1568
|
-
else
|
|
1569
|
-
warn "unexpected method name token #{name_t.inspect}"
|
|
1570
|
-
# break
|
|
1571
|
-
skip_method container
|
|
1572
|
-
|
|
1573
|
-
name = nil
|
|
1574
|
-
end
|
|
1575
|
-
|
|
1576
|
-
return name, container
|
|
1577
|
-
end
|
|
1578
|
-
|
|
1579
|
-
##
|
|
1580
|
-
# Extracts +yield+ parameters from +method+
|
|
1581
|
-
|
|
1582
|
-
def parse_method_or_yield_parameters(method = nil,
|
|
1583
|
-
modifiers = RDoc::METHOD_MODIFIERS)
|
|
1584
|
-
skip_tkspace_without_nl
|
|
1585
|
-
tk = get_tk
|
|
1586
|
-
end_token = get_end_token tk
|
|
1587
|
-
return '' unless end_token
|
|
1588
|
-
|
|
1589
|
-
nest = 0
|
|
1590
|
-
continue = false
|
|
1591
|
-
|
|
1592
|
-
while tk != nil do
|
|
1593
|
-
case tk[:kind]
|
|
1594
|
-
when :on_semicolon then
|
|
1595
|
-
break if nest == 0
|
|
1596
|
-
when :on_lbracket then
|
|
1597
|
-
nest += 1
|
|
1598
|
-
when :on_rbracket then
|
|
1599
|
-
nest -= 1
|
|
1600
|
-
when :on_lbrace then
|
|
1601
|
-
nest += 1
|
|
1602
|
-
when :on_rbrace then
|
|
1603
|
-
nest -= 1
|
|
1604
|
-
if nest <= 0
|
|
1605
|
-
# we might have a.each { |i| yield i }
|
|
1606
|
-
unget_tk(tk) if nest < 0
|
|
1607
|
-
break
|
|
1608
|
-
end
|
|
1609
|
-
when :on_lparen then
|
|
1610
|
-
nest += 1
|
|
1611
|
-
when end_token[:kind] then
|
|
1612
|
-
if end_token[:kind] == :on_rparen
|
|
1613
|
-
nest -= 1
|
|
1614
|
-
break if nest <= 0
|
|
1615
|
-
else
|
|
1616
|
-
break
|
|
1617
|
-
end
|
|
1618
|
-
when :on_rparen then
|
|
1619
|
-
nest -= 1
|
|
1620
|
-
when :on_comment, :on_embdoc then
|
|
1621
|
-
@read.pop
|
|
1622
|
-
if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and
|
|
1623
|
-
(!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then
|
|
1624
|
-
if method && method.block_params.nil? then
|
|
1625
|
-
unget_tk tk
|
|
1626
|
-
read_documentation_modifiers method, modifiers
|
|
1627
|
-
end
|
|
1628
|
-
break if !continue and nest <= 0
|
|
1629
|
-
end
|
|
1630
|
-
when :on_comma then
|
|
1631
|
-
continue = true
|
|
1632
|
-
when :on_ident then
|
|
1633
|
-
continue = false if continue
|
|
1634
|
-
end
|
|
1635
|
-
tk = get_tk
|
|
1636
|
-
end
|
|
1637
|
-
|
|
1638
|
-
get_tkread_clean(/\s+/, ' ')
|
|
1639
|
-
end
|
|
1640
|
-
|
|
1641
|
-
##
|
|
1642
|
-
# Capture the method's parameters. Along the way, look for a comment
|
|
1643
|
-
# containing:
|
|
1644
|
-
#
|
|
1645
|
-
# # yields: ....
|
|
1646
|
-
#
|
|
1647
|
-
# and add this as the block_params for the method
|
|
1648
|
-
|
|
1649
|
-
def parse_method_parameters method
|
|
1650
|
-
res = parse_method_or_yield_parameters method
|
|
1651
|
-
|
|
1652
|
-
res = "(#{res})" unless res =~ /\A\(/
|
|
1653
|
-
method.params = res unless method.params
|
|
1654
|
-
|
|
1655
|
-
return if method.block_params
|
|
1656
|
-
|
|
1657
|
-
skip_tkspace_without_nl
|
|
1658
|
-
read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
|
|
1659
|
-
end
|
|
1660
|
-
|
|
1661
|
-
##
|
|
1662
|
-
# Parses an RDoc::NormalModule in +container+ with +comment+
|
|
1663
|
-
|
|
1664
|
-
def parse_module container, single, tk, comment
|
|
1665
|
-
container, name_t, = get_class_or_module container
|
|
1666
|
-
|
|
1667
|
-
name = name_t[:text]
|
|
1668
|
-
|
|
1669
|
-
mod = container.add_module RDoc::NormalModule, name
|
|
1670
|
-
mod.ignore unless container.document_children
|
|
1671
|
-
record_location mod
|
|
1672
|
-
|
|
1673
|
-
read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
|
|
1674
|
-
mod.add_comment comment, @top_level
|
|
1675
|
-
parse_statements mod
|
|
1676
|
-
|
|
1677
|
-
# after end modifiers
|
|
1678
|
-
read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
|
|
1679
|
-
|
|
1680
|
-
@stats.add_module mod
|
|
1681
|
-
end
|
|
1682
|
-
|
|
1683
|
-
##
|
|
1684
|
-
# Parses an RDoc::Require in +context+ containing +comment+
|
|
1685
|
-
|
|
1686
|
-
def parse_require(context, comment)
|
|
1687
|
-
skip_tkspace_comment
|
|
1688
|
-
tk = get_tk
|
|
1689
|
-
|
|
1690
|
-
if :on_lparen == tk[:kind] then
|
|
1691
|
-
skip_tkspace_comment
|
|
1692
|
-
tk = get_tk
|
|
1693
|
-
end
|
|
1694
|
-
|
|
1695
|
-
name = tk[:text][1..-2] if :on_tstring == tk[:kind]
|
|
1696
|
-
|
|
1697
|
-
if name then
|
|
1698
|
-
@top_level.add_require RDoc::Require.new(name, comment)
|
|
1699
|
-
else
|
|
1700
|
-
unget_tk tk
|
|
1701
|
-
end
|
|
1702
|
-
end
|
|
1703
|
-
|
|
1704
|
-
##
|
|
1705
|
-
# Parses a rescue
|
|
1706
|
-
|
|
1707
|
-
def parse_rescue
|
|
1708
|
-
skip_tkspace_without_nl
|
|
1709
|
-
|
|
1710
|
-
while tk = get_tk
|
|
1711
|
-
case tk[:kind]
|
|
1712
|
-
when :on_nl, :on_semicolon, :on_comment then
|
|
1713
|
-
break
|
|
1714
|
-
when :on_comma then
|
|
1715
|
-
skip_tkspace_without_nl
|
|
1716
|
-
|
|
1717
|
-
get_tk if :on_nl == peek_tk[:kind]
|
|
1718
|
-
end
|
|
1719
|
-
|
|
1720
|
-
skip_tkspace_without_nl
|
|
1721
|
-
end
|
|
1722
|
-
end
|
|
1723
|
-
|
|
1724
|
-
##
|
|
1725
|
-
# Retrieve comment body without =begin/=end
|
|
1726
|
-
|
|
1727
|
-
def retrieve_comment_body(tk)
|
|
1728
|
-
if :on_embdoc == tk[:kind]
|
|
1729
|
-
tk[:text].gsub(/\A=begin.*\n/, '').gsub(/=end\n?\z/, '')
|
|
1730
|
-
else
|
|
1731
|
-
tk[:text]
|
|
1732
|
-
end
|
|
1733
|
-
end
|
|
1734
|
-
|
|
1735
|
-
##
|
|
1736
|
-
# The core of the Ruby parser.
|
|
1737
|
-
|
|
1738
|
-
def parse_statements(container, single = NORMAL, current_method = nil,
|
|
1739
|
-
comment = new_comment(''))
|
|
1740
|
-
raise 'no' unless RDoc::Comment === comment
|
|
1741
|
-
comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
|
|
1742
|
-
|
|
1743
|
-
nest = 1
|
|
1744
|
-
save_visibility = container.visibility
|
|
1745
|
-
|
|
1746
|
-
non_comment_seen = true
|
|
1747
|
-
|
|
1748
|
-
while tk = get_tk do
|
|
1749
|
-
keep_comment = false
|
|
1750
|
-
try_parse_comment = false
|
|
1751
|
-
|
|
1752
|
-
non_comment_seen = true unless (:on_comment == tk[:kind] or :on_embdoc == tk[:kind])
|
|
1753
|
-
|
|
1754
|
-
case tk[:kind]
|
|
1755
|
-
when :on_nl, :on_ignored_nl, :on_comment, :on_embdoc then
|
|
1756
|
-
if :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]
|
|
1757
|
-
skip_tkspace
|
|
1758
|
-
tk = get_tk
|
|
1759
|
-
else
|
|
1760
|
-
past_tokens = @read.size > 1 ? @read[0..-2] : []
|
|
1761
|
-
nl_position = 0
|
|
1762
|
-
past_tokens.reverse.each_with_index do |read_tk, i|
|
|
1763
|
-
if read_tk =~ /^\n$/ then
|
|
1764
|
-
nl_position = (past_tokens.size - 1) - i
|
|
1765
|
-
break
|
|
1766
|
-
elsif read_tk =~ /^#.*\n$/ then
|
|
1767
|
-
nl_position = ((past_tokens.size - 1) - i) + 1
|
|
1768
|
-
break
|
|
1769
|
-
end
|
|
1770
|
-
end
|
|
1771
|
-
comment_only_line = past_tokens[nl_position..-1].all?{ |c| c =~ /^\s+$/ }
|
|
1772
|
-
unless comment_only_line then
|
|
1773
|
-
tk = get_tk
|
|
1774
|
-
end
|
|
1775
|
-
end
|
|
1776
|
-
|
|
1777
|
-
if tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then
|
|
1778
|
-
if non_comment_seen then
|
|
1779
|
-
# Look for RDoc in a comment about to be thrown away
|
|
1780
|
-
non_comment_seen = parse_comment container, tk, comment unless
|
|
1781
|
-
comment.empty?
|
|
1782
|
-
|
|
1783
|
-
comment = ''
|
|
1784
|
-
comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
|
|
1785
|
-
end
|
|
1786
|
-
|
|
1787
|
-
line_no = nil
|
|
1788
|
-
while tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) do
|
|
1789
|
-
comment_body = retrieve_comment_body(tk)
|
|
1790
|
-
line_no = tk[:line_no] if comment.empty?
|
|
1791
|
-
comment += comment_body
|
|
1792
|
-
comment << "\n" unless comment_body =~ /\n\z/
|
|
1793
|
-
|
|
1794
|
-
if comment_body.size > 1 && comment_body =~ /\n\z/ then
|
|
1795
|
-
skip_tkspace_without_nl # leading spaces
|
|
1796
|
-
end
|
|
1797
|
-
tk = get_tk
|
|
1798
|
-
end
|
|
1799
|
-
|
|
1800
|
-
comment = new_comment comment, line_no
|
|
1801
|
-
|
|
1802
|
-
unless comment.empty? then
|
|
1803
|
-
look_for_directives_in container, comment
|
|
1804
|
-
|
|
1805
|
-
if container.done_documenting then
|
|
1806
|
-
throw :eof if RDoc::TopLevel === container
|
|
1807
|
-
container.ongoing_visibility = save_visibility
|
|
1808
|
-
end
|
|
1809
|
-
end
|
|
1810
|
-
|
|
1811
|
-
keep_comment = true
|
|
1812
|
-
else
|
|
1813
|
-
non_comment_seen = true
|
|
1814
|
-
end
|
|
1815
|
-
|
|
1816
|
-
unget_tk tk
|
|
1817
|
-
keep_comment = true
|
|
1818
|
-
container.current_line_visibility = nil
|
|
1819
|
-
|
|
1820
|
-
when :on_kw then
|
|
1821
|
-
case tk[:text]
|
|
1822
|
-
when 'class' then
|
|
1823
|
-
parse_class container, single, tk, comment
|
|
1824
|
-
|
|
1825
|
-
when 'module' then
|
|
1826
|
-
parse_module container, single, tk, comment
|
|
1827
|
-
|
|
1828
|
-
when 'def' then
|
|
1829
|
-
parse_method container, single, tk, comment
|
|
1830
|
-
|
|
1831
|
-
when 'alias' then
|
|
1832
|
-
parse_alias container, single, tk, comment unless current_method
|
|
1833
|
-
|
|
1834
|
-
when 'yield' then
|
|
1835
|
-
if current_method.nil? then
|
|
1836
|
-
warn "Warning: yield outside of method" if container.document_self
|
|
1837
|
-
else
|
|
1838
|
-
parse_yield container, single, tk, current_method
|
|
1839
|
-
end
|
|
1840
|
-
|
|
1841
|
-
when 'until', 'while' then
|
|
1842
|
-
if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
|
|
1843
|
-
nest += 1
|
|
1844
|
-
skip_optional_do_after_expression
|
|
1845
|
-
end
|
|
1846
|
-
|
|
1847
|
-
# Until and While can have a 'do', which shouldn't increase the nesting.
|
|
1848
|
-
# We can't solve the general case, but we can handle most occurrences by
|
|
1849
|
-
# ignoring a do at the end of a line.
|
|
1850
|
-
|
|
1851
|
-
# 'for' is trickier
|
|
1852
|
-
when 'for' then
|
|
1853
|
-
nest += 1
|
|
1854
|
-
skip_for_variable
|
|
1855
|
-
skip_optional_do_after_expression
|
|
1856
|
-
|
|
1857
|
-
when 'case', 'do', 'if', 'unless', 'begin' then
|
|
1858
|
-
if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
|
|
1859
|
-
nest += 1
|
|
1860
|
-
end
|
|
1861
|
-
|
|
1862
|
-
when 'super' then
|
|
1863
|
-
current_method.calls_super = true if current_method
|
|
1864
|
-
|
|
1865
|
-
when 'rescue' then
|
|
1866
|
-
parse_rescue
|
|
1867
|
-
|
|
1868
|
-
when 'end' then
|
|
1869
|
-
nest -= 1
|
|
1870
|
-
if nest == 0 then
|
|
1871
|
-
container.ongoing_visibility = save_visibility
|
|
1872
|
-
|
|
1873
|
-
parse_comment container, tk, comment unless comment.empty?
|
|
1874
|
-
|
|
1875
|
-
return
|
|
1876
|
-
end
|
|
1877
|
-
end
|
|
1878
|
-
|
|
1879
|
-
when :on_const then
|
|
1880
|
-
unless parse_constant container, tk, comment, current_method then
|
|
1881
|
-
try_parse_comment = true
|
|
1882
|
-
end
|
|
1883
|
-
|
|
1884
|
-
when :on_ident then
|
|
1885
|
-
if nest == 1 and current_method.nil? then
|
|
1886
|
-
keep_comment = parse_identifier container, single, tk, comment
|
|
1887
|
-
end
|
|
1888
|
-
|
|
1889
|
-
case tk[:text]
|
|
1890
|
-
when "require" then
|
|
1891
|
-
parse_require container, comment
|
|
1892
|
-
when "include" then
|
|
1893
|
-
parse_extend_or_include RDoc::Include, container, comment
|
|
1894
|
-
when "extend" then
|
|
1895
|
-
parse_extend_or_include RDoc::Extend, container, comment
|
|
1896
|
-
end
|
|
1897
|
-
|
|
1898
|
-
else
|
|
1899
|
-
try_parse_comment = nest == 1
|
|
1900
|
-
end
|
|
1901
|
-
|
|
1902
|
-
if try_parse_comment then
|
|
1903
|
-
non_comment_seen = parse_comment container, tk, comment unless
|
|
1904
|
-
comment.empty?
|
|
1905
|
-
|
|
1906
|
-
keep_comment = false
|
|
1907
|
-
end
|
|
1908
|
-
|
|
1909
|
-
unless keep_comment then
|
|
1910
|
-
comment = new_comment ''
|
|
1911
|
-
comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
|
|
1912
|
-
container.params = nil
|
|
1913
|
-
container.block_params = nil
|
|
1914
|
-
end
|
|
1915
|
-
|
|
1916
|
-
consume_trailing_spaces
|
|
1917
|
-
end
|
|
1918
|
-
|
|
1919
|
-
container.params = nil
|
|
1920
|
-
container.block_params = nil
|
|
1921
|
-
end
|
|
1922
|
-
|
|
1923
|
-
##
|
|
1924
|
-
# Parse up to +no+ symbol arguments
|
|
1925
|
-
|
|
1926
|
-
def parse_symbol_arg(no = nil)
|
|
1927
|
-
skip_tkspace_comment
|
|
1928
|
-
|
|
1929
|
-
tk = get_tk
|
|
1930
|
-
if tk[:kind] == :on_lparen
|
|
1931
|
-
parse_symbol_arg_paren no
|
|
1932
|
-
else
|
|
1933
|
-
parse_symbol_arg_space no, tk
|
|
1934
|
-
end
|
|
1935
|
-
end
|
|
1936
|
-
|
|
1937
|
-
##
|
|
1938
|
-
# Parses up to +no+ symbol arguments surrounded by () and places them in
|
|
1939
|
-
# +args+.
|
|
1940
|
-
|
|
1941
|
-
def parse_symbol_arg_paren no # :nodoc:
|
|
1942
|
-
args = []
|
|
1943
|
-
|
|
1944
|
-
loop do
|
|
1945
|
-
skip_tkspace_comment
|
|
1946
|
-
if tk1 = parse_symbol_in_arg
|
|
1947
|
-
args.push tk1
|
|
1948
|
-
break if no and args.size >= no
|
|
1949
|
-
end
|
|
1950
|
-
|
|
1951
|
-
skip_tkspace_comment
|
|
1952
|
-
case (tk2 = get_tk)[:kind]
|
|
1953
|
-
when :on_rparen
|
|
1954
|
-
break
|
|
1955
|
-
when :on_comma
|
|
1956
|
-
else
|
|
1957
|
-
warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
|
|
1958
|
-
break
|
|
1959
|
-
end
|
|
1960
|
-
end
|
|
1961
|
-
|
|
1962
|
-
args
|
|
1963
|
-
end
|
|
1964
|
-
|
|
1965
|
-
##
|
|
1966
|
-
# Parses up to +no+ symbol arguments separated by spaces and places them in
|
|
1967
|
-
# +args+.
|
|
1968
|
-
|
|
1969
|
-
def parse_symbol_arg_space no, tk # :nodoc:
|
|
1970
|
-
args = []
|
|
1971
|
-
|
|
1972
|
-
unget_tk tk
|
|
1973
|
-
if tk = parse_symbol_in_arg
|
|
1974
|
-
args.push tk
|
|
1975
|
-
return args if no and args.size >= no
|
|
1976
|
-
end
|
|
1977
|
-
|
|
1978
|
-
loop do
|
|
1979
|
-
skip_tkspace_without_nl
|
|
1980
|
-
|
|
1981
|
-
tk1 = get_tk
|
|
1982
|
-
if tk1.nil? || :on_comma != tk1[:kind] then
|
|
1983
|
-
unget_tk tk1
|
|
1984
|
-
break
|
|
1985
|
-
end
|
|
1986
|
-
|
|
1987
|
-
skip_tkspace_comment
|
|
1988
|
-
if tk = parse_symbol_in_arg
|
|
1989
|
-
args.push tk
|
|
1990
|
-
break if no and args.size >= no
|
|
1991
|
-
end
|
|
1992
|
-
end
|
|
1993
|
-
|
|
1994
|
-
args
|
|
1995
|
-
end
|
|
1996
|
-
|
|
1997
|
-
##
|
|
1998
|
-
# Returns symbol text from the next token
|
|
1999
|
-
|
|
2000
|
-
def parse_symbol_in_arg
|
|
2001
|
-
tk = get_tk
|
|
2002
|
-
if :on_symbol == tk[:kind] then
|
|
2003
|
-
tk[:text].sub(/^:/, '')
|
|
2004
|
-
elsif :on_tstring == tk[:kind] then
|
|
2005
|
-
tk[:text][1..-2]
|
|
2006
|
-
elsif :on_dstring == tk[:kind] or :on_ident == tk[:kind] then
|
|
2007
|
-
nil # ignore
|
|
2008
|
-
else
|
|
2009
|
-
warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
|
|
2010
|
-
nil
|
|
2011
|
-
end
|
|
2012
|
-
end
|
|
2013
|
-
|
|
2014
|
-
##
|
|
2015
|
-
# Parses statements in the top-level +container+
|
|
2016
|
-
|
|
2017
|
-
def parse_top_level_statements container
|
|
2018
|
-
comment = collect_first_comment
|
|
2019
|
-
|
|
2020
|
-
look_for_directives_in container, comment
|
|
2021
|
-
|
|
2022
|
-
throw :eof if container.done_documenting
|
|
2023
|
-
|
|
2024
|
-
@markup = comment.format
|
|
2025
|
-
|
|
2026
|
-
# HACK move if to RDoc::Context#comment=
|
|
2027
|
-
container.comment = comment if container.document_self unless comment.empty?
|
|
2028
|
-
|
|
2029
|
-
parse_statements container, NORMAL, nil, comment
|
|
2030
|
-
end
|
|
2031
|
-
|
|
2032
|
-
##
|
|
2033
|
-
# Determines the visibility in +container+ from +tk+
|
|
2034
|
-
|
|
2035
|
-
def parse_visibility(container, single, tk)
|
|
2036
|
-
vis_type, vis, singleton = get_visibility_information tk, single
|
|
2037
|
-
|
|
2038
|
-
skip_tkspace_comment false
|
|
2039
|
-
|
|
2040
|
-
ptk = peek_tk
|
|
2041
|
-
# Ryan Davis suggested the extension to ignore modifiers, because he
|
|
2042
|
-
# often writes
|
|
2043
|
-
#
|
|
2044
|
-
# protected unless $TESTING
|
|
2045
|
-
#
|
|
2046
|
-
if [:on_nl, :on_semicolon].include?(ptk[:kind]) || (:on_kw == ptk[:kind] && (['if', 'unless'].include?(ptk[:text]))) then
|
|
2047
|
-
container.ongoing_visibility = vis
|
|
2048
|
-
elsif :on_kw == ptk[:kind] && 'def' == ptk[:text]
|
|
2049
|
-
container.current_line_visibility = vis
|
|
2050
|
-
else
|
|
2051
|
-
update_visibility container, vis_type, vis, singleton
|
|
2052
|
-
end
|
|
2053
|
-
end
|
|
2054
|
-
|
|
2055
|
-
##
|
|
2056
|
-
# Parses a Module#private_constant or Module#public_constant call from +tk+.
|
|
2057
|
-
|
|
2058
|
-
def parse_constant_visibility(container, single, tk)
|
|
2059
|
-
args = parse_symbol_arg
|
|
2060
|
-
case tk[:text]
|
|
2061
|
-
when 'private_constant'
|
|
2062
|
-
vis = :private
|
|
2063
|
-
when 'public_constant'
|
|
2064
|
-
vis = :public
|
|
2065
|
-
else
|
|
2066
|
-
raise RDoc::Error, 'Unreachable'
|
|
2067
|
-
end
|
|
2068
|
-
container.set_constant_visibility_for args, vis
|
|
2069
|
-
end
|
|
2070
|
-
|
|
2071
|
-
##
|
|
2072
|
-
# Determines the block parameter for +context+
|
|
2073
|
-
|
|
2074
|
-
def parse_yield(context, single, tk, method)
|
|
2075
|
-
return if method.block_params
|
|
2076
|
-
|
|
2077
|
-
get_tkread
|
|
2078
|
-
method.block_params = parse_method_or_yield_parameters
|
|
2079
|
-
end
|
|
2080
|
-
|
|
2081
|
-
##
|
|
2082
|
-
# Directives are modifier comments that can appear after class, module, or
|
|
2083
|
-
# method names. For example:
|
|
2084
|
-
#
|
|
2085
|
-
# def fred # :yields: a, b
|
|
2086
|
-
#
|
|
2087
|
-
# or:
|
|
2088
|
-
#
|
|
2089
|
-
# class MyClass # :nodoc:
|
|
2090
|
-
#
|
|
2091
|
-
# We return the directive name and any parameters as a two element array if
|
|
2092
|
-
# the name is in +allowed+. A directive can be found anywhere up to the end
|
|
2093
|
-
# of the current line.
|
|
2094
|
-
|
|
2095
|
-
def read_directive allowed
|
|
2096
|
-
tokens = []
|
|
2097
|
-
|
|
2098
|
-
while tk = get_tk do
|
|
2099
|
-
tokens << tk
|
|
2100
|
-
|
|
2101
|
-
if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then
|
|
2102
|
-
return
|
|
2103
|
-
elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then
|
|
2104
|
-
return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/
|
|
2105
|
-
|
|
2106
|
-
directive = $1.downcase
|
|
2107
|
-
|
|
2108
|
-
return [directive, $2] if allowed.include? directive
|
|
2109
|
-
|
|
2110
|
-
return
|
|
2111
|
-
end
|
|
2112
|
-
end
|
|
2113
|
-
ensure
|
|
2114
|
-
unless tokens.length == 1 and (:on_comment == tokens.first[:kind] or :on_embdoc == tokens.first[:kind]) then
|
|
2115
|
-
tokens.reverse_each do |token|
|
|
2116
|
-
unget_tk token
|
|
1261
|
+
def visit_forwarding_super_node(node)
|
|
1262
|
+
@calls_super = true
|
|
2117
1263
|
end
|
|
2118
1264
|
end
|
|
2119
1265
|
end
|
|
2120
|
-
|
|
2121
|
-
##
|
|
2122
|
-
# Handles directives following the definition for +context+ (any
|
|
2123
|
-
# RDoc::CodeObject) if the directives are +allowed+ at this point.
|
|
2124
|
-
#
|
|
2125
|
-
# See also RDoc::Markup::PreProcess#handle_directive
|
|
2126
|
-
|
|
2127
|
-
def read_documentation_modifiers context, allowed
|
|
2128
|
-
skip_tkspace_without_nl
|
|
2129
|
-
directive, value = read_directive allowed
|
|
2130
|
-
|
|
2131
|
-
return unless directive
|
|
2132
|
-
|
|
2133
|
-
@preprocess.handle_directive '', directive, value, context do |dir, param|
|
|
2134
|
-
if %w[notnew not_new not-new].include? dir then
|
|
2135
|
-
context.dont_rename_initialize = true
|
|
2136
|
-
|
|
2137
|
-
true
|
|
2138
|
-
end
|
|
2139
|
-
end
|
|
2140
|
-
end
|
|
2141
|
-
|
|
2142
|
-
##
|
|
2143
|
-
# Records the location of this +container+ in the file for this parser and
|
|
2144
|
-
# adds it to the list of classes and modules in the file.
|
|
2145
|
-
|
|
2146
|
-
def record_location container # :nodoc:
|
|
2147
|
-
case container
|
|
2148
|
-
when RDoc::ClassModule then
|
|
2149
|
-
@top_level.add_to_classes_or_modules container
|
|
2150
|
-
end
|
|
2151
|
-
|
|
2152
|
-
container.record_location @top_level
|
|
2153
|
-
end
|
|
2154
|
-
|
|
2155
|
-
##
|
|
2156
|
-
# Scans this Ruby file for Ruby constructs
|
|
2157
|
-
|
|
2158
|
-
def scan
|
|
2159
|
-
reset
|
|
2160
|
-
|
|
2161
|
-
catch :eof do
|
|
2162
|
-
begin
|
|
2163
|
-
parse_top_level_statements @top_level
|
|
2164
|
-
|
|
2165
|
-
rescue StandardError => e
|
|
2166
|
-
if @content.include?('<%') and @content.include?('%>') then
|
|
2167
|
-
# Maybe, this is ERB.
|
|
2168
|
-
$stderr.puts "\033[2KRDoc detects ERB file. Skips it for compatibility:"
|
|
2169
|
-
$stderr.puts @file_name
|
|
2170
|
-
return
|
|
2171
|
-
end
|
|
2172
|
-
|
|
2173
|
-
if @scanner_point >= @scanner.size
|
|
2174
|
-
now_line_no = @scanner[@scanner.size - 1][:line_no]
|
|
2175
|
-
else
|
|
2176
|
-
now_line_no = peek_tk[:line_no]
|
|
2177
|
-
end
|
|
2178
|
-
first_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no }
|
|
2179
|
-
last_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no + 1 }
|
|
2180
|
-
last_tk_index = last_tk_index ? last_tk_index - 1 : @scanner.size - 1
|
|
2181
|
-
code = @scanner[first_tk_index..last_tk_index].map{ |t| t[:text] }.join
|
|
2182
|
-
|
|
2183
|
-
$stderr.puts <<-EOF
|
|
2184
|
-
|
|
2185
|
-
#{self.class} failure around line #{now_line_no} of
|
|
2186
|
-
#{@file_name}
|
|
2187
|
-
|
|
2188
|
-
EOF
|
|
2189
|
-
|
|
2190
|
-
unless code.empty? then
|
|
2191
|
-
$stderr.puts code
|
|
2192
|
-
$stderr.puts
|
|
2193
|
-
end
|
|
2194
|
-
|
|
2195
|
-
raise e
|
|
2196
|
-
end
|
|
2197
|
-
end
|
|
2198
|
-
|
|
2199
|
-
@top_level
|
|
2200
|
-
end
|
|
2201
|
-
|
|
2202
|
-
##
|
|
2203
|
-
# while, until, and for have an optional do
|
|
2204
|
-
|
|
2205
|
-
def skip_optional_do_after_expression
|
|
2206
|
-
skip_tkspace_without_nl
|
|
2207
|
-
tk = get_tk
|
|
2208
|
-
|
|
2209
|
-
b_nest = 0
|
|
2210
|
-
nest = 0
|
|
2211
|
-
|
|
2212
|
-
loop do
|
|
2213
|
-
break unless tk
|
|
2214
|
-
case tk[:kind]
|
|
2215
|
-
when :on_semicolon, :on_nl, :on_ignored_nl then
|
|
2216
|
-
break if b_nest.zero?
|
|
2217
|
-
when :on_lparen then
|
|
2218
|
-
nest += 1
|
|
2219
|
-
when :on_rparen then
|
|
2220
|
-
nest -= 1
|
|
2221
|
-
when :on_kw then
|
|
2222
|
-
case tk[:text]
|
|
2223
|
-
when 'begin'
|
|
2224
|
-
b_nest += 1
|
|
2225
|
-
when 'end'
|
|
2226
|
-
b_nest -= 1
|
|
2227
|
-
when 'do'
|
|
2228
|
-
break if nest.zero?
|
|
2229
|
-
end
|
|
2230
|
-
when :on_comment, :on_embdoc then
|
|
2231
|
-
if b_nest.zero? and "\n" == tk[:text][-1] then
|
|
2232
|
-
break
|
|
2233
|
-
end
|
|
2234
|
-
end
|
|
2235
|
-
tk = get_tk
|
|
2236
|
-
end
|
|
2237
|
-
|
|
2238
|
-
skip_tkspace_without_nl
|
|
2239
|
-
|
|
2240
|
-
get_tk if peek_tk && :on_kw == peek_tk[:kind] && 'do' == peek_tk[:text]
|
|
2241
|
-
end
|
|
2242
|
-
|
|
2243
|
-
##
|
|
2244
|
-
# skip the var [in] part of a 'for' statement
|
|
2245
|
-
|
|
2246
|
-
def skip_for_variable
|
|
2247
|
-
skip_tkspace_without_nl
|
|
2248
|
-
get_tk
|
|
2249
|
-
skip_tkspace_without_nl
|
|
2250
|
-
tk = get_tk
|
|
2251
|
-
unget_tk(tk) unless :on_kw == tk[:kind] and 'in' == tk[:text]
|
|
2252
|
-
end
|
|
2253
|
-
|
|
2254
|
-
##
|
|
2255
|
-
# Skips the next method in +container+
|
|
2256
|
-
|
|
2257
|
-
def skip_method container
|
|
2258
|
-
meth = RDoc::AnyMethod.new "", "anon"
|
|
2259
|
-
parse_method_parameters meth
|
|
2260
|
-
parse_statements container, false, meth
|
|
2261
|
-
end
|
|
2262
|
-
|
|
2263
|
-
##
|
|
2264
|
-
# Skip spaces until a comment is found
|
|
2265
|
-
|
|
2266
|
-
def skip_tkspace_comment(skip_nl = true)
|
|
2267
|
-
loop do
|
|
2268
|
-
skip_nl ? skip_tkspace : skip_tkspace_without_nl
|
|
2269
|
-
next_tk = peek_tk
|
|
2270
|
-
return if next_tk.nil? || (:on_comment != next_tk[:kind] and :on_embdoc != next_tk[:kind])
|
|
2271
|
-
get_tk
|
|
2272
|
-
end
|
|
2273
|
-
end
|
|
2274
|
-
|
|
2275
|
-
##
|
|
2276
|
-
# Updates visibility in +container+ from +vis_type+ and +vis+.
|
|
2277
|
-
|
|
2278
|
-
def update_visibility container, vis_type, vis, singleton # :nodoc:
|
|
2279
|
-
new_methods = []
|
|
2280
|
-
|
|
2281
|
-
case vis_type
|
|
2282
|
-
when 'module_function' then
|
|
2283
|
-
args = parse_symbol_arg
|
|
2284
|
-
container.set_visibility_for args, :private, false
|
|
2285
|
-
|
|
2286
|
-
container.methods_matching args do |m|
|
|
2287
|
-
s_m = m.dup
|
|
2288
|
-
record_location s_m
|
|
2289
|
-
s_m.singleton = true
|
|
2290
|
-
new_methods << s_m
|
|
2291
|
-
end
|
|
2292
|
-
when 'public_class_method', 'private_class_method' then
|
|
2293
|
-
args = parse_symbol_arg
|
|
2294
|
-
|
|
2295
|
-
container.methods_matching args, true do |m|
|
|
2296
|
-
if m.parent != container then
|
|
2297
|
-
m = m.dup
|
|
2298
|
-
record_location m
|
|
2299
|
-
new_methods << m
|
|
2300
|
-
end
|
|
2301
|
-
|
|
2302
|
-
m.visibility = vis
|
|
2303
|
-
end
|
|
2304
|
-
else
|
|
2305
|
-
args = parse_symbol_arg
|
|
2306
|
-
container.set_visibility_for args, vis, singleton
|
|
2307
|
-
end
|
|
2308
|
-
|
|
2309
|
-
new_methods.each do |method|
|
|
2310
|
-
case method
|
|
2311
|
-
when RDoc::AnyMethod then
|
|
2312
|
-
container.add_method method
|
|
2313
|
-
when RDoc::Attr then
|
|
2314
|
-
container.add_attribute method
|
|
2315
|
-
end
|
|
2316
|
-
method.visibility = vis
|
|
2317
|
-
end
|
|
2318
|
-
end
|
|
2319
|
-
|
|
2320
|
-
##
|
|
2321
|
-
# Prints +message+ to +$stderr+ unless we're being quiet
|
|
2322
|
-
|
|
2323
|
-
def warn message
|
|
2324
|
-
@options.warn make_message message
|
|
2325
|
-
end
|
|
2326
|
-
|
|
2327
1266
|
end
|