mega-max-hub 0.0.1
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 +7 -0
- data/mega-max-hub.gemspec +11 -0
- data/rdoc-8.0.0/CONTRIBUTING.md +195 -0
- data/rdoc-8.0.0/CVE-2013-0256.rdoc +49 -0
- data/rdoc-8.0.0/History.rdoc +1668 -0
- data/rdoc-8.0.0/LEGAL.rdoc +56 -0
- data/rdoc-8.0.0/LICENSE.rdoc +63 -0
- data/rdoc-8.0.0/README.md +236 -0
- data/rdoc-8.0.0/RI.md +842 -0
- data/rdoc-8.0.0/TODO.rdoc +60 -0
- data/rdoc-8.0.0/doc/markup_reference/markdown.md +659 -0
- data/rdoc-8.0.0/doc/markup_reference/rdoc.rdoc +1169 -0
- data/rdoc-8.0.0/exe/rdoc +43 -0
- data/rdoc-8.0.0/exe/ri +12 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/alias.rb +98 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/any_method.rb +387 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/attr.rb +178 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/class_module.rb +969 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/constant.rb +221 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/context/section.rb +182 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/context.rb +1238 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/extend.rb +9 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/include.rb +9 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/method_attr.rb +417 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/mixin.rb +123 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/normal_class.rb +92 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/normal_module.rb +73 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/require.rb +51 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/single_class.rb +30 -0
- data/rdoc-8.0.0/lib/rdoc/code_object/top_level.rb +286 -0
- data/rdoc-8.0.0/lib/rdoc/code_object.rb +393 -0
- data/rdoc-8.0.0/lib/rdoc/code_objects.rb +5 -0
- data/rdoc-8.0.0/lib/rdoc/comment.rb +353 -0
- data/rdoc-8.0.0/lib/rdoc/cross_reference.rb +215 -0
- data/rdoc-8.0.0/lib/rdoc/encoding.rb +120 -0
- data/rdoc-8.0.0/lib/rdoc/erb_partial.rb +18 -0
- data/rdoc-8.0.0/lib/rdoc/erbio.rb +37 -0
- data/rdoc-8.0.0/lib/rdoc/generator/aliki.rb +200 -0
- data/rdoc-8.0.0/lib/rdoc/generator/darkfish.rb +824 -0
- data/rdoc-8.0.0/lib/rdoc/generator/json_index.rb +284 -0
- data/rdoc-8.0.0/lib/rdoc/generator/markup.rb +196 -0
- data/rdoc-8.0.0/lib/rdoc/generator/pot/message_extractor.rb +68 -0
- data/rdoc-8.0.0/lib/rdoc/generator/pot/po.rb +84 -0
- data/rdoc-8.0.0/lib/rdoc/generator/pot/po_entry.rb +141 -0
- data/rdoc-8.0.0/lib/rdoc/generator/pot.rb +94 -0
- data/rdoc-8.0.0/lib/rdoc/generator/ri.rb +30 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +8 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_footer.rhtml +23 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_head.rhtml +163 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_header.rhtml +56 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_icons.rhtml +208 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_ancestors.rhtml +16 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_classes.rhtml +15 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +27 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +27 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +16 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_methods.rhtml +41 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +67 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +15 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +21 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +3 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/class.rhtml +230 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/css/rdoc.css +2181 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/index.rhtml +22 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/aliki.js +513 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/c_highlighter.js +299 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/search_controller.js +129 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/js/theme-toggle.js +112 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/page.rhtml +18 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +14 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/aliki/servlet_root.rhtml +65 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_footer.rhtml +5 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_head.rhtml +43 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +5 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +17 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +17 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +16 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +21 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml +11 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +32 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +6 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +15 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +11 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +39 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml +3 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/class.rhtml +220 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/css/fonts.css +167 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/css/rdoc.css +701 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/add.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/arrow_up.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/bug.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/delete.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/tag_blue.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/transparent.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/index.rhtml +24 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/js/darkfish.js +140 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/js/search.js +120 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/page.rhtml +19 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +21 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +65 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +72 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/json_index/js/navigation.js +105 -0
- data/rdoc-8.0.0/lib/rdoc/generator/template/json_index/js/searcher.js +271 -0
- data/rdoc-8.0.0/lib/rdoc/generator.rb +52 -0
- data/rdoc-8.0.0/lib/rdoc/i18n/locale.rb +102 -0
- data/rdoc-8.0.0/lib/rdoc/i18n/text.rb +126 -0
- data/rdoc-8.0.0/lib/rdoc/i18n.rb +10 -0
- data/rdoc-8.0.0/lib/rdoc/known_classes.rb +74 -0
- data/rdoc-8.0.0/lib/rdoc/markdown/entities.rb +2131 -0
- data/rdoc-8.0.0/lib/rdoc/markdown/literals.kpeg +21 -0
- data/rdoc-8.0.0/lib/rdoc/markdown/literals.rb +454 -0
- data/rdoc-8.0.0/lib/rdoc/markdown.kpeg +1315 -0
- data/rdoc-8.0.0/lib/rdoc/markdown.rb +16865 -0
- data/rdoc-8.0.0/lib/rdoc/markup/blank_line.rb +29 -0
- data/rdoc-8.0.0/lib/rdoc/markup/block_quote.rb +14 -0
- data/rdoc-8.0.0/lib/rdoc/markup/document.rb +164 -0
- data/rdoc-8.0.0/lib/rdoc/markup/element.rb +21 -0
- data/rdoc-8.0.0/lib/rdoc/markup/formatter.rb +285 -0
- data/rdoc-8.0.0/lib/rdoc/markup/hard_break.rb +34 -0
- data/rdoc-8.0.0/lib/rdoc/markup/heading.rb +170 -0
- data/rdoc-8.0.0/lib/rdoc/markup/include.rb +42 -0
- data/rdoc-8.0.0/lib/rdoc/markup/indented_paragraph.rb +47 -0
- data/rdoc-8.0.0/lib/rdoc/markup/inline_parser.rb +312 -0
- data/rdoc-8.0.0/lib/rdoc/markup/list.rb +101 -0
- data/rdoc-8.0.0/lib/rdoc/markup/list_item.rb +99 -0
- data/rdoc-8.0.0/lib/rdoc/markup/paragraph.rb +28 -0
- data/rdoc-8.0.0/lib/rdoc/markup/parser.rb +585 -0
- data/rdoc-8.0.0/lib/rdoc/markup/pre_process.rb +317 -0
- data/rdoc-8.0.0/lib/rdoc/markup/raw.rb +66 -0
- data/rdoc-8.0.0/lib/rdoc/markup/rule.rb +20 -0
- data/rdoc-8.0.0/lib/rdoc/markup/table.rb +64 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_ansi.rb +144 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_bs.rb +86 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_html.rb +682 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_html_crossref.rb +261 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_html_snippet.rb +287 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_joined_paragraph.rb +41 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_label.rb +84 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_markdown.rb +215 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_rdoc.rb +421 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_table_of_contents.rb +88 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_test.rb +77 -0
- data/rdoc-8.0.0/lib/rdoc/markup/to_tt_only.rb +107 -0
- data/rdoc-8.0.0/lib/rdoc/markup/verbatim.rb +83 -0
- data/rdoc-8.0.0/lib/rdoc/markup.rb +219 -0
- data/rdoc-8.0.0/lib/rdoc/options.rb +1412 -0
- data/rdoc-8.0.0/lib/rdoc/parser/c.rb +1227 -0
- data/rdoc-8.0.0/lib/rdoc/parser/changelog.rb +379 -0
- data/rdoc-8.0.0/lib/rdoc/parser/markdown.rb +22 -0
- data/rdoc-8.0.0/lib/rdoc/parser/rbs.rb +275 -0
- data/rdoc-8.0.0/lib/rdoc/parser/rd.rb +22 -0
- data/rdoc-8.0.0/lib/rdoc/parser/ruby.rb +1266 -0
- data/rdoc-8.0.0/lib/rdoc/parser/ruby_colorizer.rb +253 -0
- data/rdoc-8.0.0/lib/rdoc/parser/simple.rb +44 -0
- data/rdoc-8.0.0/lib/rdoc/parser/text.rb +11 -0
- data/rdoc-8.0.0/lib/rdoc/parser.rb +298 -0
- data/rdoc-8.0.0/lib/rdoc/rbs_helper.rb +186 -0
- data/rdoc-8.0.0/lib/rdoc/rd/block_parser.rb +1706 -0
- data/rdoc-8.0.0/lib/rdoc/rd/block_parser.ry +643 -0
- data/rdoc-8.0.0/lib/rdoc/rd/inline.rb +71 -0
- data/rdoc-8.0.0/lib/rdoc/rd/inline_parser.rb +1854 -0
- data/rdoc-8.0.0/lib/rdoc/rd/inline_parser.ry +593 -0
- data/rdoc-8.0.0/lib/rdoc/rd.rb +99 -0
- data/rdoc-8.0.0/lib/rdoc/rdoc.rb +724 -0
- data/rdoc-8.0.0/lib/rdoc/ri/driver.rb +1572 -0
- data/rdoc-8.0.0/lib/rdoc/ri/formatter.rb +6 -0
- data/rdoc-8.0.0/lib/rdoc/ri/paths.rb +171 -0
- data/rdoc-8.0.0/lib/rdoc/ri/servlet.rb +452 -0
- data/rdoc-8.0.0/lib/rdoc/ri/store.rb +6 -0
- data/rdoc-8.0.0/lib/rdoc/ri/task.rb +71 -0
- data/rdoc-8.0.0/lib/rdoc/ri.rb +21 -0
- data/rdoc-8.0.0/lib/rdoc/rubygems_hook.rb +327 -0
- data/rdoc-8.0.0/lib/rdoc/server.rb +460 -0
- data/rdoc-8.0.0/lib/rdoc/stats/normal.rb +58 -0
- data/rdoc-8.0.0/lib/rdoc/stats/quiet.rb +59 -0
- data/rdoc-8.0.0/lib/rdoc/stats/verbose.rb +44 -0
- data/rdoc-8.0.0/lib/rdoc/stats.rb +484 -0
- data/rdoc-8.0.0/lib/rdoc/store.rb +1205 -0
- data/rdoc-8.0.0/lib/rdoc/task.rb +355 -0
- data/rdoc-8.0.0/lib/rdoc/text.rb +244 -0
- data/rdoc-8.0.0/lib/rdoc/token_stream.rb +104 -0
- data/rdoc-8.0.0/lib/rdoc/tom_doc.rb +257 -0
- data/rdoc-8.0.0/lib/rdoc/version.rb +10 -0
- data/rdoc-8.0.0/lib/rdoc.rb +239 -0
- data/rdoc-8.0.0/lib/rubygems_plugin.rb +14 -0
- data/rdoc-8.0.0/man/ri.1 +249 -0
- data/rdoc-8.0.0/rdoc-logo.svg +43 -0
- data/rdoc-8.0.0/rdoc.gemspec +74 -0
- metadata +256 -0
|
@@ -0,0 +1,1266 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'prism'
|
|
4
|
+
require_relative '../rbs_helper'
|
|
5
|
+
|
|
6
|
+
# Parse and collect document from Ruby source code.
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Extracts code elements from a source file returning a TopLevel object
|
|
10
|
+
# containing the constituent file elements.
|
|
11
|
+
#
|
|
12
|
+
# RubyParser understands how to document:
|
|
13
|
+
# * classes
|
|
14
|
+
# * modules
|
|
15
|
+
# * methods
|
|
16
|
+
# * constants
|
|
17
|
+
# * aliases
|
|
18
|
+
# * private, public, protected
|
|
19
|
+
# * private_class_function, public_class_function
|
|
20
|
+
# * private_constant, public_constant
|
|
21
|
+
# * module_function
|
|
22
|
+
# * attr, attr_reader, attr_writer, attr_accessor
|
|
23
|
+
# * extra accessors given on the command line
|
|
24
|
+
# * metaprogrammed methods
|
|
25
|
+
# * require
|
|
26
|
+
# * include
|
|
27
|
+
#
|
|
28
|
+
# == Method Arguments
|
|
29
|
+
#
|
|
30
|
+
# The parser extracts the arguments from the method definition. You can
|
|
31
|
+
# override this with a custom argument definition using the :args: directive:
|
|
32
|
+
#
|
|
33
|
+
# ##
|
|
34
|
+
# # This method tries over and over until it is tired
|
|
35
|
+
#
|
|
36
|
+
# def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try
|
|
37
|
+
# puts thing_to_try
|
|
38
|
+
# go_go_go thing_to_try, tries - 1
|
|
39
|
+
# end
|
|
40
|
+
#
|
|
41
|
+
# If you have a more-complex set of overrides you can use the :call-seq:
|
|
42
|
+
# directive:
|
|
43
|
+
#
|
|
44
|
+
# ##
|
|
45
|
+
# # This method can be called with a range or an offset and length
|
|
46
|
+
# #
|
|
47
|
+
# # :call-seq:
|
|
48
|
+
# # my_method(Range)
|
|
49
|
+
# # my_method(offset, length)
|
|
50
|
+
#
|
|
51
|
+
# def my_method(*args)
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# The parser extracts +yield+ expressions from method bodies to gather the
|
|
55
|
+
# yielded argument names. If your method manually calls a block instead of
|
|
56
|
+
# yielding or you want to override the discovered argument names use
|
|
57
|
+
# the :yields: directive:
|
|
58
|
+
#
|
|
59
|
+
# ##
|
|
60
|
+
# # My method is awesome
|
|
61
|
+
#
|
|
62
|
+
# def my_method(&block) # :yields: happy, times
|
|
63
|
+
# block.call 1, 2
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# == Metaprogrammed Methods
|
|
67
|
+
#
|
|
68
|
+
# To pick up a metaprogrammed method, the parser looks for a comment starting
|
|
69
|
+
# with '##' before a metaprogramming method call:
|
|
70
|
+
#
|
|
71
|
+
# ##
|
|
72
|
+
# # This is a meta-programmed method!
|
|
73
|
+
#
|
|
74
|
+
# add_my_method :meta_method, :arg1, :arg2
|
|
75
|
+
#
|
|
76
|
+
# The parser looks at the first argument to determine the name, in
|
|
77
|
+
# this example, :meta_method. If a name cannot be found, a warning is printed
|
|
78
|
+
# and 'unknown' is used.
|
|
79
|
+
#
|
|
80
|
+
# You can force the name of a method using the :method: directive:
|
|
81
|
+
#
|
|
82
|
+
# ##
|
|
83
|
+
# # :method: some_method!
|
|
84
|
+
#
|
|
85
|
+
# By default, meta-methods are instance methods. To indicate that a method is
|
|
86
|
+
# a singleton method instead use the :singleton-method: directive:
|
|
87
|
+
#
|
|
88
|
+
# ##
|
|
89
|
+
# # :singleton-method:
|
|
90
|
+
#
|
|
91
|
+
# You can also use the :singleton-method: directive with a name:
|
|
92
|
+
#
|
|
93
|
+
# ##
|
|
94
|
+
# # :singleton-method: some_method!
|
|
95
|
+
#
|
|
96
|
+
# You can define arguments for metaprogrammed methods via either the
|
|
97
|
+
# \:call-seq:, :arg: or :args: directives.
|
|
98
|
+
#
|
|
99
|
+
# Additionally you can mark a method as an attribute by
|
|
100
|
+
# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like
|
|
101
|
+
# for :method:, the name is optional.
|
|
102
|
+
#
|
|
103
|
+
# ##
|
|
104
|
+
# # :attr_reader: my_attr_name
|
|
105
|
+
#
|
|
106
|
+
# == Hidden methods and attributes
|
|
107
|
+
#
|
|
108
|
+
# You can provide documentation for methods that don't appear using
|
|
109
|
+
# the :method:, :singleton-method: and :attr: directives:
|
|
110
|
+
#
|
|
111
|
+
# ##
|
|
112
|
+
# # :attr_writer: ghost_writer
|
|
113
|
+
# # There is an attribute here, but you can't see it!
|
|
114
|
+
#
|
|
115
|
+
# ##
|
|
116
|
+
# # :method: ghost_method
|
|
117
|
+
# # There is a method here, but you can't see it!
|
|
118
|
+
#
|
|
119
|
+
# ##
|
|
120
|
+
# # this is a comment for a regular method
|
|
121
|
+
#
|
|
122
|
+
# def regular_method() end
|
|
123
|
+
#
|
|
124
|
+
# Note that by default, the :method: directive will be ignored if there is a
|
|
125
|
+
# standard rdocable item following it.
|
|
126
|
+
|
|
127
|
+
class RDoc::Parser::Ruby < RDoc::Parser
|
|
128
|
+
|
|
129
|
+
parse_files_matching(/\.rbw?$/)
|
|
130
|
+
|
|
131
|
+
# Matches an RBS inline type annotation line: #: followed by whitespace
|
|
132
|
+
RBS_SIG_LINE = /\A#:\s/ # :nodoc:
|
|
133
|
+
|
|
134
|
+
attr_accessor :visibility
|
|
135
|
+
attr_reader :container, :singleton, :in_proc_block
|
|
136
|
+
|
|
137
|
+
def initialize(top_level, content, options, stats)
|
|
138
|
+
super
|
|
139
|
+
|
|
140
|
+
content = handle_tab_width(content)
|
|
141
|
+
|
|
142
|
+
@size = 0
|
|
143
|
+
@token_listeners = nil
|
|
144
|
+
content = RDoc::Encoding.remove_magic_comment content
|
|
145
|
+
@content = content
|
|
146
|
+
@markup = @options.markup
|
|
147
|
+
@track_visibility = :nodoc != @options.visibility
|
|
148
|
+
@encoding = @options.encoding
|
|
149
|
+
|
|
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
|
|
187
|
+
end
|
|
188
|
+
|
|
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.
|
|
191
|
+
|
|
192
|
+
def record_location(container) # :nodoc:
|
|
193
|
+
case container
|
|
194
|
+
when RDoc::ClassModule then
|
|
195
|
+
@top_level.add_to_classes_or_modules container
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
container.record_location @top_level
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Scans this Ruby file for Ruby constructs
|
|
202
|
+
|
|
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
|
|
214
|
+
|
|
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
|
|
219
|
+
|
|
220
|
+
@program_node.accept(RDocVisitor.new(self, @top_level, @store))
|
|
221
|
+
process_comments_until(@lines.size + 1)
|
|
222
|
+
end
|
|
223
|
+
|
|
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
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Assign AST node to a line.
|
|
231
|
+
# This is used to show meta-method source code in the documentation.
|
|
232
|
+
|
|
233
|
+
def prepare_line_nodes(node) # :nodoc:
|
|
234
|
+
case node
|
|
235
|
+
when Prism::CallNode, Prism::DefNode
|
|
236
|
+
@line_nodes[node.location.start_line] ||= node
|
|
237
|
+
end
|
|
238
|
+
node.compact_child_nodes.each do |child|
|
|
239
|
+
prepare_line_nodes(child)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
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
|
|
272
|
+
else
|
|
273
|
+
consecutive_comments << (current = [comment])
|
|
274
|
+
end
|
|
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
|
|
296
|
+
|
|
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
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Creates an RDoc::Method on +container+ from +comment+ if there is a
|
|
307
|
+
# Signature section in the comment
|
|
308
|
+
|
|
309
|
+
def parse_comment_tomdoc(container, comment, line_no, start_line)
|
|
310
|
+
return unless signature = RDoc::TomDoc.signature(comment)
|
|
311
|
+
|
|
312
|
+
name, = signature.split %r%[ \(]%, 2
|
|
313
|
+
|
|
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
|
|
319
|
+
|
|
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 }
|
|
324
|
+
|
|
325
|
+
container.add_method meth
|
|
326
|
+
meth.comment = comment
|
|
327
|
+
@stats.add_method meth
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def has_modifier_nodoc?(line_no) # :nodoc:
|
|
331
|
+
@modifier_comments[line_no]&.match?(/\A#\s*:nodoc:/)
|
|
332
|
+
end
|
|
333
|
+
|
|
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)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
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 || []
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Handles meta method comments
|
|
354
|
+
|
|
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
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
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
|
|
386
|
+
end
|
|
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
|
|
392
|
+
else
|
|
393
|
+
tokens = []
|
|
394
|
+
end
|
|
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)
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Processes consecutive comments that were not linked to any documentable code until the given line number
|
|
435
|
+
|
|
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)
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# Skips all undocumentable consecutive comments until the given line number.
|
|
451
|
+
# Undocumentable comments are comments written inside `def` or inside undocumentable class/module
|
|
452
|
+
|
|
453
|
+
def skip_comments_until(line_no_until)
|
|
454
|
+
while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
|
|
455
|
+
@unprocessed_comments.shift
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# Returns consecutive comment linked to the given line number
|
|
460
|
+
|
|
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)
|
|
465
|
+
end
|
|
466
|
+
|
|
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).
|
|
470
|
+
|
|
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]
|
|
487
|
+
end
|
|
488
|
+
|
|
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
|
|
492
|
+
|
|
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
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Returns syntax highlighted tokens of the given node
|
|
502
|
+
|
|
503
|
+
def syntax_highlighted_tokens(node)
|
|
504
|
+
RDoc::Parser::RubyColorizer.partial_colorize(@content, node, @prism_tokens)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Handles `public :foo, :bar` `private :foo, :bar` and `protected :foo, :bar`
|
|
508
|
+
|
|
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
|
|
516
|
+
else
|
|
517
|
+
m.visibility = visibility
|
|
518
|
+
end
|
|
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
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# Handles `module_function :foo, :bar`
|
|
532
|
+
|
|
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
|
|
541
|
+
end
|
|
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
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
|
|
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
|
|
558
|
+
|
|
559
|
+
# Handles `alias foo bar` and `alias_method :foo, :bar`
|
|
560
|
+
|
|
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
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
# Handles `attr :a, :b`, `attr_reader :a, :b`, `attr_writer :a, :b` and `attr_accessor :a, :b`
|
|
577
|
+
|
|
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
|
|
582
|
+
|
|
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
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Adds includes/extends. Module name is resolved to full before adding.
|
|
596
|
+
|
|
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
|
|
609
|
+
|
|
610
|
+
# Handle `include Foo, Bar`
|
|
611
|
+
|
|
612
|
+
def add_includes(names, line_no) # :nodoc:
|
|
613
|
+
add_includes_extends(names, RDoc::Include, line_no)
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Handle `extend Foo, Bar`
|
|
617
|
+
|
|
618
|
+
def add_extends(names, line_no) # :nodoc:
|
|
619
|
+
add_includes_extends(names, RDoc::Extend, line_no)
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
# Adds a method defined by `def` syntax
|
|
623
|
+
|
|
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
|
|
628
|
+
|
|
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
|
|
645
|
+
|
|
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
|
|
679
|
+
else
|
|
680
|
+
meth.name = 'new'
|
|
681
|
+
meth.singleton = true
|
|
682
|
+
meth.visibility = :public
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
|
|
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.
|
|
690
|
+
|
|
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
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
# Adds module or class
|
|
787
|
+
|
|
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
|
|
792
|
+
|
|
793
|
+
owner, name = find_or_create_lexical_constant_owner_name(module_name)
|
|
794
|
+
return unless owner
|
|
795
|
+
|
|
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)
|
|
816
|
+
end
|
|
817
|
+
|
|
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
|
|
826
|
+
|
|
827
|
+
private
|
|
828
|
+
|
|
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.
|
|
833
|
+
|
|
834
|
+
def extract_type_signature!(text, start_line)
|
|
835
|
+
return nil unless text.include?('#:')
|
|
836
|
+
|
|
837
|
+
lines = text.lines
|
|
838
|
+
sig_lines, doc_lines = lines.partition { |l| l.match?(RBS_SIG_LINE) }
|
|
839
|
+
return nil if sig_lines.empty?
|
|
840
|
+
|
|
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?
|
|
845
|
+
|
|
846
|
+
warn_invalid_type_signature(type_signature_lines, first_sig_line)
|
|
847
|
+
type_signature_lines
|
|
848
|
+
end
|
|
849
|
+
|
|
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
|
|
857
|
+
|
|
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
|
|
864
|
+
|
|
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)
|
|
875
|
+
end
|
|
876
|
+
end
|
|
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
|
|
927
|
+
end
|
|
928
|
+
|
|
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
|
|
936
|
+
|
|
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)
|
|
942
|
+
end
|
|
943
|
+
|
|
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)
|
|
953
|
+
end
|
|
954
|
+
else
|
|
955
|
+
@scanner.skip_comments_until(node.location.end_line)
|
|
956
|
+
end
|
|
957
|
+
end
|
|
958
|
+
|
|
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)
|
|
974
|
+
end
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
def visit_singleton_class_node(node)
|
|
978
|
+
@scanner.process_comments_until(node.location.start_line - 1)
|
|
979
|
+
|
|
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
|
|
985
|
+
|
|
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
|
|
1010
|
+
|
|
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)
|
|
1129
|
+
|
|
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)
|
|
1133
|
+
else
|
|
1134
|
+
# `module_function def something.foo` should be ignored
|
|
1135
|
+
return if arg.receiver
|
|
1136
|
+
end
|
|
1137
|
+
# `module_function def foo; end` or `private_class_method def self.foo; end`
|
|
1138
|
+
[arg.name.to_s]
|
|
1139
|
+
end
|
|
1140
|
+
end
|
|
1141
|
+
|
|
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
|
|
1151
|
+
|
|
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
|
|
1158
|
+
|
|
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
|
|
1164
|
+
|
|
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
|
|
1170
|
+
|
|
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
|
|
1179
|
+
end
|
|
1180
|
+
end
|
|
1181
|
+
|
|
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)
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
def _visit_call_include(call_node)
|
|
1191
|
+
return if @scanner.in_proc_block
|
|
1192
|
+
|
|
1193
|
+
names = constant_arguments_names(call_node)
|
|
1194
|
+
line_no = call_node.location.start_line
|
|
1195
|
+
return unless names
|
|
1196
|
+
|
|
1197
|
+
if @scanner.singleton
|
|
1198
|
+
@scanner.add_extends(names, line_no)
|
|
1199
|
+
else
|
|
1200
|
+
@scanner.add_includes(names, line_no)
|
|
1201
|
+
end
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
def _visit_call_extend(call_node)
|
|
1205
|
+
return if @scanner.in_proc_block
|
|
1206
|
+
|
|
1207
|
+
names = constant_arguments_names(call_node)
|
|
1208
|
+
@scanner.add_extends(names, call_node.location.start_line) if names && !@scanner.singleton
|
|
1209
|
+
end
|
|
1210
|
+
|
|
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
|
|
1216
|
+
|
|
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
|
|
1222
|
+
|
|
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
|
|
1228
|
+
|
|
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
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1240
|
+
attr_reader :params, :yields, :calls_super
|
|
1241
|
+
|
|
1242
|
+
def initialize
|
|
1243
|
+
@params = nil
|
|
1244
|
+
@calls_super = false
|
|
1245
|
+
@yields = []
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
def visit_def_node(node)
|
|
1249
|
+
# stop traverse inside nested def
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
def visit_yield_node(node)
|
|
1253
|
+
@yields << (node.arguments&.slice || '')
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
def visit_super_node(node)
|
|
1257
|
+
@calls_super = true
|
|
1258
|
+
super
|
|
1259
|
+
end
|
|
1260
|
+
|
|
1261
|
+
def visit_forwarding_super_node(node)
|
|
1262
|
+
@calls_super = true
|
|
1263
|
+
end
|
|
1264
|
+
end
|
|
1265
|
+
end
|
|
1266
|
+
end
|