rdoc 7.2.0 → 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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +3 -4
  3. data/LICENSE.rdoc +4 -0
  4. data/README.md +43 -2
  5. data/doc/markup_reference/markdown.md +104 -3
  6. data/lib/rdoc/code_object/alias.rb +2 -8
  7. data/lib/rdoc/code_object/any_method.rb +11 -6
  8. data/lib/rdoc/code_object/attr.rb +11 -6
  9. data/lib/rdoc/code_object/class_module.rb +62 -32
  10. data/lib/rdoc/code_object/constant.rb +29 -3
  11. data/lib/rdoc/code_object/context/section.rb +4 -35
  12. data/lib/rdoc/code_object/context.rb +39 -34
  13. data/lib/rdoc/code_object/method_attr.rb +9 -15
  14. data/lib/rdoc/code_object/mixin.rb +2 -2
  15. data/lib/rdoc/code_object/top_level.rb +9 -3
  16. data/lib/rdoc/code_object.rb +2 -4
  17. data/lib/rdoc/comment.rb +0 -65
  18. data/lib/rdoc/cross_reference.rb +7 -27
  19. data/lib/rdoc/encoding.rb +3 -3
  20. data/lib/rdoc/generator/aliki.rb +17 -0
  21. data/lib/rdoc/generator/darkfish.rb +12 -6
  22. data/lib/rdoc/generator/json_index.rb +2 -2
  23. data/lib/rdoc/generator/markup.rb +56 -31
  24. data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
  25. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  26. data/lib/rdoc/generator/template/aliki/_head.rhtml +1 -1
  27. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  28. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  29. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  30. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
  31. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  32. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  33. data/lib/rdoc/generator/template/aliki/class.rhtml +56 -46
  34. data/lib/rdoc/generator/template/aliki/css/rdoc.css +337 -111
  35. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  36. data/lib/rdoc/generator/template/aliki/js/aliki.js +20 -18
  37. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  38. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  39. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  40. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  41. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  42. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  43. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  46. data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
  47. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
  48. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  49. data/lib/rdoc/i18n/text.rb +3 -3
  50. data/lib/rdoc/markdown.kpeg +15 -10
  51. data/lib/rdoc/markdown.rb +289 -104
  52. data/lib/rdoc/markup/document.rb +2 -2
  53. data/lib/rdoc/markup/formatter.rb +24 -34
  54. data/lib/rdoc/markup/heading.rb +1 -4
  55. data/lib/rdoc/markup/indented_paragraph.rb +1 -1
  56. data/lib/rdoc/markup/list.rb +2 -2
  57. data/lib/rdoc/markup/list_item.rb +2 -2
  58. data/lib/rdoc/markup/pre_process.rb +0 -25
  59. data/lib/rdoc/markup/to_ansi.rb +1 -1
  60. data/lib/rdoc/markup/to_bs.rb +1 -1
  61. data/lib/rdoc/markup/to_html.rb +131 -53
  62. data/lib/rdoc/markup/to_html_crossref.rb +97 -71
  63. data/lib/rdoc/markup/to_html_snippet.rb +5 -5
  64. data/lib/rdoc/markup/to_joined_paragraph.rb +0 -5
  65. data/lib/rdoc/markup/to_label.rb +2 -2
  66. data/lib/rdoc/markup/to_markdown.rb +1 -1
  67. data/lib/rdoc/markup/to_rdoc.rb +2 -2
  68. data/lib/rdoc/markup/to_table_of_contents.rb +1 -1
  69. data/lib/rdoc/markup/to_tt_only.rb +0 -7
  70. data/lib/rdoc/markup/verbatim.rb +1 -1
  71. data/lib/rdoc/options.rb +36 -51
  72. data/lib/rdoc/parser/c.rb +7 -6
  73. data/lib/rdoc/parser/rbs.rb +275 -0
  74. data/lib/rdoc/parser/ruby.rb +954 -2066
  75. data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
  76. data/lib/rdoc/parser.rb +3 -2
  77. data/lib/rdoc/rbs_helper.rb +186 -0
  78. data/lib/rdoc/rdoc.rb +196 -24
  79. data/lib/rdoc/ri/driver.rb +8 -2
  80. data/lib/rdoc/ri/paths.rb +1 -1
  81. data/lib/rdoc/{servlet.rb → ri/servlet.rb} +5 -5
  82. data/lib/rdoc/ri.rb +4 -3
  83. data/lib/rdoc/rubygems_hook.rb +11 -11
  84. data/lib/rdoc/server.rb +460 -0
  85. data/lib/rdoc/stats.rb +147 -124
  86. data/lib/rdoc/store.rb +212 -4
  87. data/lib/rdoc/task.rb +16 -15
  88. data/lib/rdoc/text.rb +1 -118
  89. data/lib/rdoc/token_stream.rb +11 -33
  90. data/lib/rdoc/version.rb +1 -1
  91. data/lib/rdoc.rb +35 -7
  92. data/lib/rubygems_plugin.rb +2 -11
  93. data/rdoc-logo.svg +43 -0
  94. data/rdoc.gemspec +6 -4
  95. metadata +35 -18
  96. data/lib/rdoc/code_object/anon_class.rb +0 -10
  97. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  98. data/lib/rdoc/code_object/meta_method.rb +0 -6
  99. data/lib/rdoc/parser/prism_ruby.rb +0 -1112
  100. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  101. data/lib/rdoc/parser/ruby_tools.rb +0 -163
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1acd5d230eb6cc33e92e6ead29ef4edfd11d238750073c151197675b9d2ecef7
4
- data.tar.gz: 765310288cb7611ae3990d238a894e9bd1e2d3431c2389c412f0a9407699a4ad
3
+ metadata.gz: a89bb304f22c095d76899a316b1ec9eefdb803303046da663dcd6c3bd52c370d
4
+ data.tar.gz: 2d76488b188447465d43934b24ff7ef3d1ec6c6f314512d86e8b7e0eb4185268
5
5
  SHA512:
6
- metadata.gz: b3f79da244c49a5f13485ca9cec594aebd9cbcf9e2a8be2543aa186947ea645aac4ec783f4d3a19b9197ffa7b9e3df53e89dc774adf7ef4c394597c186039a76
7
- data.tar.gz: c13a7678b03b25bbe56c854f7314fe50b8df2784d85d04b765294f5fd32baefb92a702e66233007689f1c4a65d7141c6e428af89e5953ce5e19976418e0fd76b
6
+ metadata.gz: d16d33de20366fadd59956e72dbffe115b0837ff10e37282bfec7b5420ebb5d177ddede87bafb2f735d9b5aca944558d6f60634004020c0d023dcef40852bc3d
7
+ data.tar.gz: d0105f405dd7f6c9debbe3ec1b47d0365a637a68bd291bda10b446cc5094929a6f40cec90a57981641f8d0741a42bf1447c03dda2b0772a44b3b9927b5b52717
data/CONTRIBUTING.md CHANGED
@@ -146,7 +146,7 @@ bundle exec rake coverage
146
146
  RDoc ships with two HTML themes:
147
147
 
148
148
  - **Aliki** (default) - Modern theme with improved styling and navigation
149
- - **Darkfish** (deprecated) - Classic theme, will be removed in v8.0
149
+ - **Darkfish** (deprecated) - Classic theme, will be removed in v9.0
150
150
 
151
151
  New feature development should focus on the Aliki theme. Darkfish will continue to receive bug fixes but no new features.
152
152
 
@@ -160,13 +160,12 @@ lib/rdoc/
160
160
  ├── version.rb # Version constant
161
161
  ├── task.rb # Rake task integration
162
162
  ├── parser/ # Source code parsers
163
- │ ├── ruby.rb # Ruby code parser
163
+ │ ├── ruby.rb # Prism-based Ruby parser
164
164
  │ ├── c.rb # C extension parser
165
- │ ├── prism_ruby.rb # Prism-based Ruby parser
166
165
  │ └── ...
167
166
  ├── generator/ # Documentation generators
168
167
  │ ├── aliki.rb # HTML generator (default theme)
169
- │ ├── darkfish.rb # HTML generator (deprecated, will be removed in v8.0)
168
+ │ ├── darkfish.rb # HTML generator (deprecated, will be removed in v9.0)
170
169
  │ ├── markup.rb # Markup format generator
171
170
  │ ├── ri.rb # RI command generator
172
171
  │ └── template/ # ERB templates
data/LICENSE.rdoc CHANGED
@@ -1,3 +1,7 @@
1
+ :stopdoc:
2
+ SPDX-License-Identifier: Ruby or GPL-2.0-only
3
+ :startdoc:
4
+
1
5
  = License
2
6
 
3
7
  RDoc is copyrighted free software.
data/README.md CHANGED
@@ -3,6 +3,10 @@
3
3
  - GitHub: [https://github.com/ruby/rdoc](https://github.com/ruby/rdoc)
4
4
  - Issues: [https://github.com/ruby/rdoc/issues](https://github.com/ruby/rdoc/issues)
5
5
 
6
+ <p align="center" class="rdoc-logo">
7
+ <img src="rdoc-logo.svg" alt="RDoc" width="168" height="198">
8
+ </p>
9
+
6
10
  ## Description
7
11
 
8
12
  RDoc produces HTML and command-line documentation for Ruby projects. RDoc includes the `rdoc` and `ri` tools for generating and displaying documentation from the command-line.
@@ -37,7 +41,9 @@ rdoc --main README.md
37
41
 
38
42
  You'll find information on the various formatting tricks you can use in comment blocks in the documentation this generates.
39
43
 
40
- RDoc uses file extensions to determine how to process each file. File names ending `.rb` and `.rbw` are assumed to be Ruby source. Files ending `.c` are parsed as C files. All other files are assumed to contain just Markup-style markup (with or without leading `#` comment markers). If directory names are passed to RDoc, they are scanned recursively for C and Ruby source files only.
44
+ RDoc uses file extensions to determine how to process each file. File names ending `.rb` and `.rbw` are assumed to be Ruby source. Files ending `.c` are parsed as C files. Files ending `.rbs` are parsed as RBS signature files. All other files are assumed to contain just Markup-style markup (with or without leading `#` comment markers). If directory names are passed to RDoc, they are scanned recursively for C, Ruby, and RBS source files.
45
+
46
+ RBS files can document classes, modules, methods, attributes, and constants. When RBS declarations match objects already documented from Ruby source, their comments and type signatures extend the existing documentation.
41
47
 
42
48
  To generate documentation using `rake` see [RDoc::Task](https://ruby.github.io/rdoc/RDoc/Task.html).
43
49
 
@@ -159,7 +165,7 @@ To determine how well your project is documented run `rdoc -C lib` to get a docu
159
165
  RDoc ships with two built-in themes:
160
166
 
161
167
  - **Aliki** (default) - A modern, clean theme with improved navigation and search
162
- - **Darkfish** (deprecated) - The classic theme, will be removed in v8.0
168
+ - **Darkfish** (deprecated) - The classic theme, will be removed in v9.0
163
169
 
164
170
  To use the Darkfish theme instead of the default Aliki theme:
165
171
 
@@ -180,6 +186,41 @@ There are also a few community-maintained themes for RDoc:
180
186
 
181
187
  Please follow the theme's README for usage instructions.
182
188
 
189
+ ## Live Preview Server
190
+
191
+ RDoc includes a built-in server for previewing documentation while you edit source files. It parses your code once on startup, then watches for changes and auto-refreshes the browser.
192
+
193
+ ```shell
194
+ rdoc --server
195
+ ```
196
+
197
+ This starts a server at `http://localhost:4000`. You can specify a different port:
198
+
199
+ ```shell
200
+ rdoc --server=8080
201
+ ```
202
+
203
+ Or use the Rake task:
204
+
205
+ ```shell
206
+ rake rdoc:server
207
+ ```
208
+
209
+ ### How It Works
210
+
211
+ - Parses all source files on startup and serves pages from memory using the Aliki theme
212
+ - A background thread polls file mtimes every second
213
+ - When a file changes, only that file is re-parsed — the browser refreshes automatically
214
+ - New files are detected and added; deleted files are removed
215
+
216
+ **No external dependencies.** The server uses Ruby's built-in `TCPServer` (`socket` stdlib) — no WEBrick or other gems required.
217
+
218
+ ### Limitations
219
+
220
+ - **Reopened classes and file deletion.** If a class is defined across multiple files (e.g. `Foo` in both `a.rb` and `b.rb`), deleting one file removes the entire class from the store, including parts from the other file. Saving the remaining file triggers a re-parse that restores it.
221
+ - **Full cache invalidation.** Any file change clears all cached pages. This is simple and correct — rendering is fast (~ms per page), parsing is the expensive part and is done incrementally.
222
+ - **No HTTPS or HTTP/2.** The server is intended for local development preview only.
223
+
183
224
  ## Bugs
184
225
 
185
226
  See [CONTRIBUTING.md](CONTRIBUTING.md) for information on filing a bug report. It's OK to file a bug report for anything you're having a problem with. If you can't figure out how to make RDoc produce the output you like that is probably a documentation bug.
@@ -98,7 +98,9 @@ Use triple backticks with an optional language identifier:
98
98
  end
99
99
  ```
100
100
 
101
- Supported language for syntax highlighting: `ruby`, `rb` (alias to `ruby`), and `c`.
101
+ Supported languages for syntax highlighting: `ruby` (and `rb` alias) with server-side
102
+ highlighting, and `c`, `bash`/`sh`/`shell`/`console` with client-side JavaScript highlighting.
103
+ Other info strings are accepted and added as a CSS class but receive no highlighting.
102
104
 
103
105
  ### Blockquotes
104
106
 
@@ -420,6 +422,9 @@ For example:
420
422
  * [Link to Blockquotes](#blockquotes)
421
423
  * [Link to Anchor Links](#anchor-links)
422
424
 
425
+ When multiple headings produce the same anchor, RDoc appends `-1`, `-2`, etc.
426
+ to subsequent duplicates, matching GitHub's behavior.
427
+
423
428
  ## Footnotes
424
429
 
425
430
  ### Reference Footnotes
@@ -535,7 +540,7 @@ See [rdoc.rdoc](rdoc.rdoc) for complete directive documentation.
535
540
  | Headings | `= Heading` | `# Heading` |
536
541
  | Bold | `*word*` | `**word**` |
537
542
  | Italic | `_word_` | `*word*` |
538
- | Monospace | `+word+` | `` `word` `` |
543
+ | Monospace | `+word+` or `` `word` `` | `` `word` `` |
539
544
  | Links | `{text}[url]` | `[text](url)` |
540
545
  | Code blocks | Indent beyond margin | Indent 4 spaces or fence |
541
546
  | Block quotes | `>>>` | `>` |
@@ -551,8 +556,104 @@ See [rdoc.rdoc](rdoc.rdoc) for complete directive documentation.
551
556
 
552
557
  3. **Footnotes are collapsed** - Multiple paragraphs in a footnote become a single paragraph.
553
558
 
554
- 4. **Syntax highlighting** - Only `ruby` and `c` are supported for fenced code blocks.
559
+ 4. **Syntax highlighting** - Only `ruby`/`rb` (server-side) and `c`, `bash`/`sh`/`shell`/`console` (client-side) receive syntax highlighting. Other info strings are accepted but not highlighted.
555
560
 
556
561
  5. **Fenced code blocks** - Only triple backticks are supported. Tilde fences (`~~~`) are not supported as they conflict with strikethrough syntax. Four or more backticks for nesting are also not supported.
557
562
 
558
563
  6. **Auto-linking** - RDoc automatically links class and method names in output, even without explicit link syntax.
564
+
565
+ ## Comparison with GitHub Flavored Markdown (GFM)
566
+
567
+ This section compares RDoc's Markdown implementation with the
568
+ [GitHub Flavored Markdown Spec](https://github.github.com/gfm/) (Version 0.29-gfm, 2019-04-06).
569
+
570
+ ### Block Elements
571
+
572
+ | Feature | GFM | RDoc | Notes |
573
+ |---------|:---:|:----:|-------|
574
+ | ATX Headings (`#`) | ✅ | ✅ | Both support levels 1-6, optional closing `#` |
575
+ | Setext Headings | ✅ | ✅ | `=` for H1, `-` for H2 |
576
+ | Paragraphs | ✅ | ✅ | Full match |
577
+ | Indented Code Blocks | ✅ | ✅ | 4 spaces or 1 tab |
578
+ | Fenced Code (backticks) | ✅ 3+ | ⚠️ 3 only | RDoc doesn't support 4+ backticks for nesting |
579
+ | Fenced Code (tildes) | ✅ `~~~` | ❌ | Conflicts with strikethrough syntax |
580
+ | Info strings (language) | ✅ any | ⚠️ limited | `ruby`/`rb`, `c`, and `bash`/`sh`/`shell`/`console` highlighted; others accepted as CSS class |
581
+ | Blockquotes | ✅ | ✅ | Full match, nested supported |
582
+ | Lazy Continuation | ✅ | ⚠️ | Continuation text is included in blockquote but line break is lost (becomes a space) |
583
+ | Bullet Lists | ✅ | ✅ | `*`, `+`, `-` supported |
584
+ | Ordered Lists | ✅ `.` `)` | ⚠️ `.` only | RDoc doesn't support `)` delimiter; numbers are always renumbered from 1 |
585
+ | Nested Lists | ✅ | ✅ | 4-space indentation |
586
+ | Tables | ✅ | ✅ | Full alignment support |
587
+ | Thematic Breaks | ✅ | ✅ | `---`, `***`, `___` |
588
+ | HTML Blocks | ✅ 7 types | ⚠️ | See below |
589
+
590
+ #### HTML Blocks
591
+
592
+ GFM defines 7 types of HTML blocks:
593
+
594
+ | Type | Description | GFM | RDoc | Notes |
595
+ |------|-------------|:---:|:----:|-------|
596
+ | 1 | `<script>`, `<pre>` | ✅ | ✅ | |
597
+ | 1 | `<style>` | ✅ | ❌ | Available via `css` extension (disabled by default) |
598
+ | 2 | HTML comments `<!-- -->` | ✅ | ✅ | |
599
+ | 3 | Processing instructions `<? ?>` | ✅ | ❌ | |
600
+ | 4 | Declarations `<!DOCTYPE>` | ✅ | ❌ | |
601
+ | 5 | CDATA `<![CDATA[ ]]>` | ✅ | ❌ | |
602
+ | 6 | Block-level tags | ✅ | ⚠️ | |
603
+ | 7 | Any complete open/close tag | ✅ | ❌ | |
604
+
605
+ RDoc uses a whitelist of block-level tags defined in
606
+ [lib/rdoc/markdown.kpeg](https://github.com/ruby/rdoc/blob/master/lib/rdoc/markdown.kpeg)
607
+ (see `HtmlBlockInTags`). HTML5 semantic elements like `<article>`, `<section>`,
608
+ `<nav>`, `<header>`, `<footer>` are not supported.
609
+
610
+ ### Inline Elements
611
+
612
+ | Feature | GFM | RDoc | Notes |
613
+ |---------|:---:|:----:|-------|
614
+ | Emphasis `*text*` `_text_` | ✅ | ⚠️ | Intraword emphasis not supported (see [Notes](#notes-and-limitations)) |
615
+ | Strong `**text**` `__text__` | ✅ | ✅ | Full match |
616
+ | Combined `***text***` | ✅ | ✅ | Full match |
617
+ | Code spans | ✅ | ✅ | Multiple backticks supported |
618
+ | Inline links | ✅ | ✅ | Full match |
619
+ | Reference links | ✅ | ✅ | Full match |
620
+ | Link titles | ✅ | ⚠️ | Parsed but not rendered |
621
+ | Images | ✅ | ✅ | Full match |
622
+ | Autolinks `<url>` | ✅ | ✅ | Full match |
623
+ | Hard line breaks | ✅ | ⚠️ | 2+ trailing spaces only; backslash `\` at EOL not supported |
624
+ | Backslash escapes | ✅ | ⚠️ | Subset of GFM's escapable characters (e.g., `~` not escapable) |
625
+ | HTML entities | ✅ | ✅ | Named, decimal, hex |
626
+ | Inline HTML | ✅ | ⚠️ | `<b>` converted to `<strong>`, `<i>` to `<em>`; `<strong>` itself is escaped |
627
+
628
+ ### GFM Extensions
629
+
630
+ | Feature | GFM | RDoc | Notes |
631
+ |---------|:---:|:----:|-------|
632
+ | Strikethrough `~~text~~` | ✅ | ✅ | Full match |
633
+ | Task Lists `[ ]` `[x]` | ✅ | ❌ | Not supported |
634
+ | Extended Autolinks | ✅ | ⚠️ | See below |
635
+ | Disallowed Raw HTML | ✅ | ❌ | No security filtering |
636
+
637
+ #### GFM Extended Autolinks
638
+
639
+ GFM automatically converts certain text patterns into links without requiring
640
+ angle brackets (`<>`). RDoc also auto-links URLs and `www.` prefixes through
641
+ its cross-reference system, but the behavior differs from GFM.
642
+
643
+ GFM recognizes these patterns:
644
+
645
+ - `www.example.com` — text starting with `www.` followed by a valid domain
646
+ - `https://example.com` — URLs starting with `http://` or `https://`
647
+ - `user@example.com` — valid email addresses
648
+
649
+ RDoc auto-links `www.` prefixes and `http://`/`https://` URLs similarly to GFM.
650
+ However, bare email addresses like `user@example.com` are not auto-linked;
651
+ use `<user@example.com>` instead.
652
+
653
+ ### RDoc-Specific Features (not in GFM)
654
+
655
+ - [Definition Lists](#definition-lists)
656
+ - [Footnotes](#footnotes)
657
+ - [Cross-references](#cross-references)
658
+ - [Anchor Links](#anchor-links)
659
+ - [Directives](#directives)
@@ -26,18 +26,12 @@ class RDoc::Alias < RDoc::CodeObject
26
26
  attr_reader :singleton
27
27
 
28
28
  ##
29
- # Source file token stream
30
-
31
- attr_reader :text
32
-
33
- ##
34
- # Creates a new Alias with a token stream of +text+ that aliases +old_name+
29
+ # Creates a new Alias that aliases +old_name+
35
30
  # to +new_name+, has +comment+ and is a +singleton+ context.
36
31
 
37
- def initialize(text, old_name, new_name, comment, singleton: false)
32
+ def initialize(old_name, new_name, comment, singleton: false)
38
33
  super()
39
34
 
40
- @text = text
41
35
  @singleton = singleton
42
36
  @old_name = old_name
43
37
  @new_name = new_name
@@ -13,8 +13,10 @@ class RDoc::AnyMethod < RDoc::MethodAttr
13
13
  # 3::
14
14
  # RDoc 4.1
15
15
  # Added is_alias_for
16
+ # 4::
17
+ # Added type_signature_lines (serialized as joined string)
16
18
 
17
- MARSHAL_VERSION = 3 # :nodoc:
19
+ MARSHAL_VERSION = 4 # :nodoc:
18
20
 
19
21
  ##
20
22
  # Don't rename \#initialize to \::new
@@ -37,10 +39,10 @@ class RDoc::AnyMethod < RDoc::MethodAttr
37
39
  include RDoc::TokenStream
38
40
 
39
41
  ##
40
- # Creates a new AnyMethod with a token stream +text+ and +name+
42
+ # Creates a new AnyMethod with name +name+
41
43
 
42
- def initialize(text, name, singleton: false)
43
- super(text, name, singleton: singleton)
44
+ def initialize(name, singleton: false)
45
+ super(name, singleton: singleton)
44
46
 
45
47
  @c_function = nil
46
48
  @dont_rename_initialize = false
@@ -53,13 +55,14 @@ class RDoc::AnyMethod < RDoc::MethodAttr
53
55
  # Adds +an_alias+ as an alias for this method in +context+.
54
56
 
55
57
  def add_alias(an_alias, context = nil)
56
- method = self.class.new an_alias.text, an_alias.new_name, singleton: singleton
58
+ method = self.class.new an_alias.new_name, singleton: singleton
57
59
 
58
60
  method.record_location an_alias.file
59
61
  method.params = self.params
60
62
  method.visibility = self.visibility
61
63
  method.comment = an_alias.comment
62
64
  method.is_alias_for = self
65
+ method.type_signature_lines = self.type_signature_lines
63
66
  @aliases << method
64
67
  context.add_method method if context
65
68
  method
@@ -166,6 +169,7 @@ class RDoc::AnyMethod < RDoc::MethodAttr
166
169
  @parent.class,
167
170
  @section.title,
168
171
  is_alias_for,
172
+ @type_signature_lines&.join("\n"),
169
173
  ]
170
174
  end
171
175
 
@@ -204,9 +208,10 @@ class RDoc::AnyMethod < RDoc::MethodAttr
204
208
  @parent_title = array[13]
205
209
  @section_title = array[14]
206
210
  @is_alias_for = array[15]
211
+ @type_signature_lines = array[16]&.split("\n")
207
212
 
208
213
  array[8].each do |new_name, document|
209
- add_alias RDoc::Alias.new(nil, @name, new_name, RDoc::Comment.from_document(document), singleton: @singleton)
214
+ add_alias RDoc::Alias.new(@name, new_name, RDoc::Comment.from_document(document), singleton: @singleton)
210
215
  end
211
216
 
212
217
  @parent_name ||= if @full_name =~ /#/ then
@@ -10,8 +10,10 @@ class RDoc::Attr < RDoc::MethodAttr
10
10
  # RDoc 4
11
11
  # Added parent name and class
12
12
  # Added section title
13
+ # 4::
14
+ # Added type_signature_lines (serialized as joined string)
13
15
 
14
- MARSHAL_VERSION = 3 # :nodoc:
16
+ MARSHAL_VERSION = 4 # :nodoc:
15
17
 
16
18
  ##
17
19
  # Is the attribute readable ('R'), writable ('W') or both ('RW')?
@@ -19,11 +21,11 @@ class RDoc::Attr < RDoc::MethodAttr
19
21
  attr_accessor :rw
20
22
 
21
23
  ##
22
- # Creates a new Attr with body +text+, +name+, read/write status +rw+ and
24
+ # Creates a new Attr with +name+, read/write status +rw+ and
23
25
  # +comment+. +singleton+ marks this as a class attribute.
24
26
 
25
- def initialize(text, name, rw, comment, singleton: false)
26
- super(text, name, singleton: singleton)
27
+ def initialize(name, rw, comment, singleton: false)
28
+ super(name, singleton: singleton)
27
29
 
28
30
  @rw = rw
29
31
  self.comment = comment
@@ -44,10 +46,11 @@ class RDoc::Attr < RDoc::MethodAttr
44
46
 
45
47
  def add_alias(an_alias, context)
46
48
  access_type = an_alias.new_name.end_with?('=') ? 'W' : 'R'
47
- new_attr = self.class.new(text, an_alias.new_name, access_type, comment, singleton: singleton)
49
+ new_attr = self.class.new(an_alias.new_name, access_type, comment, singleton: singleton)
48
50
  new_attr.record_location an_alias.file
49
51
  new_attr.visibility = self.visibility
50
52
  new_attr.is_alias_for = self
53
+ new_attr.type_signature_lines = self.type_signature_lines
51
54
  @aliases << new_attr
52
55
  context.add_attribute new_attr
53
56
  new_attr
@@ -108,7 +111,8 @@ class RDoc::Attr < RDoc::MethodAttr
108
111
  @file.relative_name,
109
112
  @parent.full_name,
110
113
  @parent.class,
111
- @section.title
114
+ @section.title,
115
+ @type_signature_lines&.join("\n"),
112
116
  ]
113
117
  end
114
118
 
@@ -140,6 +144,7 @@ class RDoc::Attr < RDoc::MethodAttr
140
144
  @parent_name = array[8]
141
145
  @parent_class = array[9]
142
146
  @section_title = array[10]
147
+ @type_signature_lines = array[11]&.split("\n")
143
148
 
144
149
  @file = RDoc::TopLevel.new array[7] if version > 1
145
150
 
@@ -30,22 +30,20 @@ class RDoc::ClassModule < RDoc::Context
30
30
  attr_accessor :constant_aliases
31
31
 
32
32
  ##
33
- # An array of `[comment, location]` pairs documenting this class/module.
33
+ # A hash of <tt>{ location => [comments] }</tt> documenting this class/module.
34
34
  # Use #add_comment to add comments.
35
35
  #
36
+ # Ruby hashes maintain insertion order, so comments render in the order
37
+ # they were first added. Each location maps to an array of comments,
38
+ # allowing a class reopened in the same file to accumulate multiple comments.
39
+ #
36
40
  # Before marshalling:
37
- # - +comment+ is a String
38
41
  # - +location+ is an RDoc::TopLevel
42
+ # - +comments+ are Strings
39
43
  #
40
44
  # After unmarshalling:
41
- # - +comment+ is an RDoc::Markup::Document
42
45
  # - +location+ is a filename String
43
- #
44
- # These type changes are acceptable (for now) because:
45
- # - +comment+: Both String and Document respond to #empty?, and #parse
46
- # returns Document as-is (see RDoc::Text#parse)
47
- # - +location+: Only used by #parse to set Document#file, which accepts
48
- # both TopLevel (extracts relative_name) and String
46
+ # - +comments+ are RDoc::Markup::Documents
49
47
 
50
48
  attr_accessor :comment_location
51
49
 
@@ -63,8 +61,8 @@ class RDoc::ClassModule < RDoc::Context
63
61
  def self.from_module(class_type, mod)
64
62
  klass = class_type.new mod.name
65
63
 
66
- mod.comment_location.each do |comment, location|
67
- klass.add_comment comment, location
64
+ mod.comment_location.each do |location, comments|
65
+ comments.each { |comment| klass.add_comment comment, location }
68
66
  end
69
67
 
70
68
  klass.parent = mod.parent
@@ -125,7 +123,7 @@ class RDoc::ClassModule < RDoc::Context
125
123
  @is_alias_for = nil
126
124
  @name = name
127
125
  @superclass = superclass
128
- @comment_location = [] # Array of [comment, location] pairs
126
+ @comment_location = {} # Hash of { location => [comments] }
129
127
 
130
128
  super()
131
129
  end
@@ -147,11 +145,7 @@ class RDoc::ClassModule < RDoc::Context
147
145
  normalize_comment comment
148
146
  end
149
147
 
150
- if location.parser == RDoc::Parser::C
151
- @comment_location.delete_if { |(_, l)| l == location }
152
- end
153
-
154
- @comment_location << [comment, location]
148
+ (@comment_location[location] ||= []) << comment
155
149
 
156
150
  self.comment = original
157
151
  end
@@ -270,7 +264,7 @@ class RDoc::ClassModule < RDoc::Context
270
264
  def documented?
271
265
  return true if @received_nodoc
272
266
  return false if @comment_location.empty?
273
- @comment_location.any? { |comment, _| not comment.empty? }
267
+ @comment_location.each_value.any? { |comments| comments.any? { |c| not c.empty? } }
274
268
  end
275
269
 
276
270
  ##
@@ -411,16 +405,16 @@ class RDoc::ClassModule < RDoc::Context
411
405
  @comment = RDoc::Comment.from_document document
412
406
 
413
407
  @comment_location = if document.parts.first.is_a?(RDoc::Markup::Document)
414
- document.parts.map { |doc| [doc, doc.file] }
408
+ document.parts.group_by(&:file)
415
409
  else
416
- [[document, document.file]]
410
+ { document.file => [document] }
417
411
  end
418
412
 
419
413
  array[5].each do |name, rw, visibility, singleton, file|
420
414
  singleton ||= false
421
415
  visibility ||= :public
422
416
 
423
- attr = RDoc::Attr.new nil, name, rw, nil, singleton: singleton
417
+ attr = RDoc::Attr.new name, rw, nil, singleton: singleton
424
418
 
425
419
  add_attribute attr
426
420
  attr.visibility = visibility
@@ -447,7 +441,7 @@ class RDoc::ClassModule < RDoc::Context
447
441
  @visibility = visibility
448
442
 
449
443
  methods.each do |name, file|
450
- method = RDoc::AnyMethod.new nil, name, singleton: type == 'class'
444
+ method = RDoc::AnyMethod.new name, singleton: type == 'class'
451
445
  method.record_location RDoc::TopLevel.new file
452
446
  add_method method
453
447
  end
@@ -495,9 +489,9 @@ class RDoc::ClassModule < RDoc::Context
495
489
  @comment = RDoc::Comment.from_document(document)
496
490
 
497
491
  @comment_location = if document.parts.first.is_a?(RDoc::Markup::Document)
498
- document.parts.map { |doc| [doc, doc.file] }
492
+ document.parts.group_by(&:file)
499
493
  else
500
- [[document, document.file]]
494
+ { document.file => [document] }
501
495
  end
502
496
  end
503
497
 
@@ -643,11 +637,13 @@ class RDoc::ClassModule < RDoc::Context
643
637
  case comment_location
644
638
  when String then
645
639
  super
646
- when Array then
647
- docs = comment_location.map do |comment, location|
648
- doc = super comment
649
- doc.file = location
650
- doc
640
+ when Hash then
641
+ docs = comment_location.flat_map do |location, comments|
642
+ comments.map do |comment|
643
+ doc = super comment
644
+ doc.file = location
645
+ doc
646
+ end
651
647
  end
652
648
 
653
649
  RDoc::Markup::Document.new(*docs)
@@ -677,7 +673,7 @@ class RDoc::ClassModule < RDoc::Context
677
673
  # module or class return the name of the latter.
678
674
 
679
675
  def name_for_path
680
- is_alias_for ? is_alias_for.full_name : full_name
676
+ is_alias_for ? is_alias_for.name_for_path : full_name
681
677
  end
682
678
 
683
679
  ##
@@ -745,12 +741,24 @@ class RDoc::ClassModule < RDoc::Context
745
741
  # Returns an HTML snippet of the first comment for search results.
746
742
 
747
743
  def search_snippet
748
- first_comment = @comment_location.first&.first
744
+ first_comment = @comment_location.each_value.first&.first
749
745
  return '' unless first_comment && !first_comment.empty?
750
746
 
751
747
  snippet(first_comment)
752
748
  end
753
749
 
750
+ ##
751
+ # Rebuilds +@comment+ from the current +@comment_location+ entries,
752
+ # skipping any empty placeholders.
753
+
754
+ def rebuild_comment_from_location
755
+ texts = @comment_location.each_value.flat_map { |comments|
756
+ comments.filter_map { |c| c.to_s unless c.empty? }
757
+ }
758
+ merged = texts.join("\n---\n")
759
+ @comment = merged.empty? ? '' : RDoc::Comment.new(merged)
760
+ end
761
+
754
762
  ##
755
763
  # Sets the store for this class or module and its contained code objects.
756
764
 
@@ -839,7 +847,16 @@ class RDoc::ClassModule < RDoc::Context
839
847
 
840
848
  def update_aliases
841
849
  constants.each do |const|
842
- next unless cm = const.is_alias_for
850
+ cm = const.is_alias_for
851
+ cm ||= const.resolved_alias_target if const.is_a?(RDoc::Constant)
852
+ next unless cm
853
+
854
+ # Resolve chained aliases (A = B = C) to the real class/module.
855
+ cm = @store.find_class_or_module(cm.full_name) || cm
856
+ while (target = cm.is_alias_for)
857
+ cm = target
858
+ end
859
+
843
860
  cm_alias = cm.dup
844
861
  cm_alias.name = const.name
845
862
 
@@ -851,6 +868,19 @@ class RDoc::ClassModule < RDoc::Context
851
868
  end
852
869
  cm_alias.full_name = nil # force update for new parent
853
870
 
871
+ # Don't clobber a real (non-alias) class/module already living at this
872
+ # name. Mirrors the BasicObject = BlankSlate guard in
873
+ # Context#add_module_alias. Existing alias copies (set by
874
+ # add_module_alias or a previous update_aliases pass) carry is_alias_for,
875
+ # so they're still overwritable here.
876
+ existing = @store.find_class_or_module(cm_alias.full_name)
877
+ next if existing && !existing.is_alias_for
878
+
879
+ # Persist a lazy-resolved target so Stats#report_constants and
880
+ # Constant#marshal_dump observe the alias relationship. Skipped
881
+ # aliases (above) intentionally leave the constant unmarked.
882
+ const.is_alias_for ||= cm
883
+
854
884
  cm_alias.aliases.clear
855
885
  cm_alias.is_alias_for = cm
856
886
 
@@ -26,6 +26,14 @@ class RDoc::Constant < RDoc::CodeObject
26
26
 
27
27
  attr_accessor :visibility
28
28
 
29
+ ##
30
+ # The constant path on the RHS when the RHS is a bare constant reference
31
+ # (+Foo = Bar+ or +Foo = Bar::Baz+). Captured at parse time so
32
+ # #resolved_alias_target doesn't have to re-derive it from the textual
33
+ # #value. nil for other RHS shapes.
34
+
35
+ attr_accessor :is_alias_for_path
36
+
29
37
  ##
30
38
  # Creates a new constant with +name+, +value+ and +comment+
31
39
 
@@ -35,8 +43,9 @@ class RDoc::Constant < RDoc::CodeObject
35
43
  @name = name
36
44
  @value = value
37
45
 
38
- @is_alias_for = nil
39
- @visibility = :public
46
+ @is_alias_for = nil
47
+ @is_alias_for_path = nil
48
+ @visibility = :public
40
49
 
41
50
  self.comment = comment
42
51
  end
@@ -83,7 +92,10 @@ class RDoc::Constant < RDoc::CodeObject
83
92
  end
84
93
 
85
94
  ##
86
- # The module or class this constant is an alias for
95
+ # The module or class this constant is an alias for, when one was recorded
96
+ # explicitly (by RDoc::Context#add_module_alias, RDoc::ClassModule#update_aliases,
97
+ # or ri marshal load). Pure accessor; see #resolved_alias_target for the
98
+ # opportunistic lookup path.
87
99
 
88
100
  def is_alias_for
89
101
  case @is_alias_for
@@ -96,6 +108,20 @@ class RDoc::Constant < RDoc::CodeObject
96
108
  end
97
109
  end
98
110
 
111
+ ##
112
+ # Returns the class/module this constant *would* alias if #is_alias_for_path
113
+ # was set by the parser and that path resolves to a known class/module, or
114
+ # nil. Used to support `Const = RHS` parsed before `class RHS;end` is defined
115
+ # in another file. Pure lookup; does not mutate state. Honors :nodoc:
116
+ # (returns nil if document_self is false). Note that module nesting
117
+ # information is lost, so constant lookup is inaccurate.
118
+
119
+ def resolved_alias_target
120
+ return nil unless document_self
121
+ return nil unless @is_alias_for_path
122
+ parent.find_module_named(@is_alias_for_path)
123
+ end
124
+
99
125
  def inspect # :nodoc:
100
126
  "#<%s:0x%x %s::%s>" % [
101
127
  self.class, object_id,