rdoc 6.15.1 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +196 -0
  3. data/History.rdoc +1 -1
  4. data/LEGAL.rdoc +6 -0
  5. data/README.md +90 -7
  6. data/doc/markup_reference/markdown.md +558 -0
  7. data/doc/markup_reference/rdoc.rdoc +1169 -0
  8. data/lib/rdoc/code_object/any_method.rb +15 -7
  9. data/lib/rdoc/code_object/class_module.rb +62 -11
  10. data/lib/rdoc/code_object/constant.rb +9 -0
  11. data/lib/rdoc/code_object/context/section.rb +20 -1
  12. data/lib/rdoc/code_object/method_attr.rb +13 -1
  13. data/lib/rdoc/code_object/top_level.rb +31 -18
  14. data/lib/rdoc/comment.rb +190 -8
  15. data/lib/rdoc/cross_reference.rb +30 -21
  16. data/lib/rdoc/generator/aliki.rb +183 -0
  17. data/lib/rdoc/generator/darkfish.rb +8 -2
  18. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +8 -0
  19. data/lib/rdoc/generator/template/aliki/_footer.rhtml +23 -0
  20. data/lib/rdoc/generator/template/aliki/_head.rhtml +158 -0
  21. data/lib/rdoc/generator/template/aliki/_header.rhtml +56 -0
  22. data/lib/rdoc/generator/template/aliki/_icons.rhtml +208 -0
  23. data/lib/rdoc/generator/template/aliki/_sidebar_ancestors.rhtml +16 -0
  24. data/lib/rdoc/generator/template/aliki/_sidebar_classes.rhtml +15 -0
  25. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +25 -0
  26. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +25 -0
  27. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +16 -0
  28. data/lib/rdoc/generator/template/aliki/_sidebar_methods.rhtml +41 -0
  29. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +67 -0
  30. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +15 -0
  31. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +21 -0
  32. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +3 -0
  33. data/lib/rdoc/generator/template/aliki/class.rhtml +220 -0
  34. data/lib/rdoc/generator/template/aliki/css/rdoc.css +1963 -0
  35. data/lib/rdoc/generator/template/aliki/index.rhtml +22 -0
  36. data/lib/rdoc/generator/template/aliki/js/aliki.js +505 -0
  37. data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +299 -0
  38. data/lib/rdoc/generator/template/aliki/js/search_controller.js +129 -0
  39. data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
  40. data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
  41. data/lib/rdoc/generator/template/aliki/js/theme-toggle.js +112 -0
  42. data/lib/rdoc/generator/template/aliki/page.rhtml +18 -0
  43. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +14 -0
  44. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +65 -0
  45. data/lib/rdoc/generator/template/darkfish/_head.rhtml +2 -7
  46. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  47. data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +1 -0
  48. data/lib/rdoc/generator/template/darkfish/class.rhtml +11 -11
  49. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -0
  50. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +1 -1
  51. data/lib/rdoc/generator/template/json_index/js/searcher.js +5 -1
  52. data/lib/rdoc/generator.rb +1 -0
  53. data/lib/rdoc/markdown.kpeg +1 -5
  54. data/lib/rdoc/markdown.rb +1 -5
  55. data/lib/rdoc/markup/attribute_manager.rb +28 -1
  56. data/lib/rdoc/markup/blank_line.rb +25 -23
  57. data/lib/rdoc/markup/element.rb +21 -0
  58. data/lib/rdoc/markup/hard_break.rb +30 -27
  59. data/lib/rdoc/markup/heading.rb +166 -77
  60. data/lib/rdoc/markup/pre_process.rb +34 -10
  61. data/lib/rdoc/markup/raw.rb +52 -55
  62. data/lib/rdoc/markup/table.rb +48 -40
  63. data/lib/rdoc/markup/to_ansi.rb +4 -0
  64. data/lib/rdoc/markup/to_bs.rb +4 -0
  65. data/lib/rdoc/markup/to_html.rb +37 -15
  66. data/lib/rdoc/markup/to_html_crossref.rb +24 -5
  67. data/lib/rdoc/markup/to_label.rb +11 -1
  68. data/lib/rdoc/markup/to_rdoc.rb +11 -3
  69. data/lib/rdoc/markup/verbatim.rb +1 -1
  70. data/lib/rdoc/markup.rb +3 -2
  71. data/lib/rdoc/options.rb +21 -10
  72. data/lib/rdoc/parser/c.rb +15 -46
  73. data/lib/rdoc/parser/changelog.rb +8 -0
  74. data/lib/rdoc/parser/prism_ruby.rb +121 -113
  75. data/lib/rdoc/parser/ruby.rb +8 -8
  76. data/lib/rdoc/parser/ruby_tools.rb +5 -7
  77. data/lib/rdoc/parser/simple.rb +4 -21
  78. data/lib/rdoc/rdoc.rb +1 -0
  79. data/lib/rdoc/rubygems_hook.rb +3 -3
  80. data/lib/rdoc/text.rb +16 -1
  81. data/lib/rdoc/token_stream.rb +17 -9
  82. data/lib/rdoc/tom_doc.rb +1 -1
  83. data/lib/rdoc/version.rb +1 -1
  84. data/rdoc.gemspec +3 -3
  85. metadata +36 -9
  86. data/CONTRIBUTING.rdoc +0 -219
  87. data/ExampleMarkdown.md +0 -39
  88. data/ExampleRDoc.rdoc +0 -210
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Aliki Search Implementation
3
+ *
4
+ * Search algorithm with the following priorities:
5
+ * 1. Exact full_name match always wins (for namespace/method queries)
6
+ * 2. Exact name match gets high priority
7
+ * 3. Match types:
8
+ * - Namespace queries (::) and method queries (# or .) match against full_name
9
+ * - Regular queries match against unqualified name
10
+ * - Prefix (10000) > substring (5000) > fuzzy (1000)
11
+ * 4. First character determines type priority:
12
+ * - Starts with lowercase: methods first
13
+ * - Starts with uppercase: classes/modules/constants first
14
+ * 5. Within same type priority:
15
+ * - Unqualified match > qualified match
16
+ * - Shorter name > longer name
17
+ * 6. Class methods > instance methods
18
+ * 7. Result limit: 30
19
+ * 8. Minimum query length: 1 character
20
+ */
21
+
22
+ var MAX_RESULTS = 30;
23
+ var MIN_QUERY_LENGTH = 1;
24
+
25
+ /*
26
+ * Scoring constants - organized in tiers where each tier dominates lower tiers.
27
+ * This ensures match type always beats type priority, etc.
28
+ *
29
+ * Tier 0: Exact matches (immediate return)
30
+ * Tier 1: Match type (prefix > substring > fuzzy)
31
+ * Tier 2: Exact name bonus
32
+ * Tier 3: Type priority (method vs class based on query case)
33
+ * Tier 4: Minor bonuses (top-level, class method, name length)
34
+ */
35
+ var SCORE_EXACT_FULL_NAME = 1000000; // Tier 0: Query exactly matches full_name
36
+ var SCORE_MATCH_PREFIX = 10000; // Tier 1: Query is prefix of name
37
+ var SCORE_MATCH_SUBSTRING = 5000; // Tier 1: Query is substring of name
38
+ var SCORE_MATCH_FUZZY = 1000; // Tier 1: Query chars appear in order
39
+ var SCORE_EXACT_NAME = 500; // Tier 2: Name exactly equals query
40
+ var SCORE_TYPE_PRIORITY = 100; // Tier 3: Preferred type (method/class)
41
+ var SCORE_TOP_LEVEL = 50; // Tier 4: Top-level over namespaced
42
+ var SCORE_CLASS_METHOD = 10; // Tier 4: Class method over instance method
43
+
44
+ /**
45
+ * Check if all characters in query appear in order in target
46
+ * e.g., "addalias" fuzzy matches "add_foo_alias"
47
+ */
48
+ function fuzzyMatch(target, query) {
49
+ var ti = 0;
50
+ for (var qi = 0; qi < query.length; qi++) {
51
+ ti = target.indexOf(query[qi], ti);
52
+ if (ti === -1) return false;
53
+ ti++;
54
+ }
55
+ return true;
56
+ }
57
+
58
+ /**
59
+ * Parse and normalize a search query
60
+ * @param {string} query - The raw search query
61
+ * @returns {Object} Parsed query with normalized form and flags
62
+ */
63
+ function parseQuery(query) {
64
+ // Lowercase for case-insensitive matching (so "hash" finds both Hash class and #hash methods)
65
+ var normalized = query.toLowerCase();
66
+ var isNamespaceQuery = query.includes('::');
67
+ var isMethodQuery = query.includes('#') || query.includes('.');
68
+
69
+ // Normalize . to :: (RDoc uses :: for class methods in full_name)
70
+ if (query.includes('.')) {
71
+ normalized = normalized.replace(/\./g, '::');
72
+ }
73
+
74
+ return {
75
+ original: query,
76
+ normalized: normalized,
77
+ isNamespaceQuery: isNamespaceQuery,
78
+ isMethodQuery: isMethodQuery,
79
+ // Namespace and method queries match against full_name instead of name
80
+ matchesFullName: isNamespaceQuery || isMethodQuery,
81
+ // If query starts with lowercase, prioritize methods; otherwise prioritize classes/modules/constants
82
+ prioritizeMethod: !/^[A-Z]/.test(query)
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Main search function
88
+ * @param {string} query - The search query
89
+ * @param {Array} index - The search index to search in
90
+ * @returns {Array} Array of matching entries, sorted by relevance
91
+ */
92
+ function search(query, index) {
93
+ if (!query || query.length < MIN_QUERY_LENGTH) {
94
+ return [];
95
+ }
96
+
97
+ var q = parseQuery(query);
98
+ var results = [];
99
+
100
+ for (var i = 0; i < index.length; i++) {
101
+ var entry = index[i];
102
+ var score = computeScore(entry, q);
103
+
104
+ if (score !== null) {
105
+ results.push({ entry: entry, score: score });
106
+ }
107
+ }
108
+
109
+ results.sort(function(a, b) {
110
+ return b.score - a.score;
111
+ });
112
+
113
+ return results.slice(0, MAX_RESULTS).map(function(r) {
114
+ return r.entry;
115
+ });
116
+ }
117
+
118
+ /**
119
+ * Compute the relevance score for an entry
120
+ * @param {Object} entry - The search index entry
121
+ * @param {Object} q - Parsed query from parseQuery()
122
+ * @returns {number|null} Score or null if no match
123
+ */
124
+ function computeScore(entry, q) {
125
+ var name = entry.name;
126
+ var fullName = entry.full_name;
127
+ var type = entry.type;
128
+
129
+ var nameLower = name.toLowerCase();
130
+ var fullNameLower = fullName.toLowerCase();
131
+
132
+ // Exact full_name match (e.g., "Array#filter" matches Array#filter)
133
+ if (q.matchesFullName && fullNameLower === q.normalized) {
134
+ return SCORE_EXACT_FULL_NAME;
135
+ }
136
+
137
+ var matchScore = 0;
138
+ var target = q.matchesFullName ? fullNameLower : nameLower;
139
+
140
+ if (target.startsWith(q.normalized)) {
141
+ matchScore = SCORE_MATCH_PREFIX; // Prefix (e.g., "Arr" matches "Array")
142
+ } else if (target.includes(q.normalized)) {
143
+ matchScore = SCORE_MATCH_SUBSTRING; // Substring (e.g., "ray" matches "Array")
144
+ } else if (fuzzyMatch(target, q.normalized)) {
145
+ matchScore = SCORE_MATCH_FUZZY; // Fuzzy (e.g., "addalias" matches "add_foo_alias")
146
+ } else {
147
+ return null;
148
+ }
149
+
150
+ var score = matchScore;
151
+ var isMethod = (type === 'instance_method' || type === 'class_method');
152
+
153
+ if (q.prioritizeMethod ? isMethod : !isMethod) {
154
+ score += SCORE_TYPE_PRIORITY;
155
+ }
156
+
157
+ if (type === 'class_method') score += SCORE_CLASS_METHOD;
158
+ if (name === fullName) score += SCORE_TOP_LEVEL; // Top-level (Hash) > namespaced (Foo::Hash)
159
+ if (nameLower === q.normalized) score += SCORE_EXACT_NAME; // Exact name match
160
+ score -= name.length;
161
+
162
+ return score;
163
+ }
164
+
165
+ /**
166
+ * SearchRanker class for compatibility with the Search UI
167
+ * Provides ready() and find() interface
168
+ */
169
+ function SearchRanker(index) {
170
+ this.index = index;
171
+ this.handlers = [];
172
+ }
173
+
174
+ SearchRanker.prototype.ready = function(fn) {
175
+ this.handlers.push(fn);
176
+ };
177
+
178
+ SearchRanker.prototype.find = function(query) {
179
+ var q = parseQuery(query);
180
+ var rawResults = search(query, this.index);
181
+ var results = rawResults.map(function(entry) {
182
+ return formatResult(entry, q);
183
+ });
184
+
185
+ var _this = this;
186
+ this.handlers.forEach(function(fn) {
187
+ fn.call(_this, results, true);
188
+ });
189
+ };
190
+
191
+ /**
192
+ * Format a search result entry for display
193
+ */
194
+ function formatResult(entry, q) {
195
+ var result = {
196
+ title: highlightMatch(entry.full_name, q),
197
+ path: entry.path,
198
+ type: entry.type
199
+ };
200
+
201
+ if (entry.snippet) {
202
+ result.snippet = entry.snippet;
203
+ }
204
+
205
+ return result;
206
+ }
207
+
208
+ /**
209
+ * Add highlight markers (\u0001 and \u0002) to matching portions of text
210
+ * @param {string} text - The text to highlight
211
+ * @param {Object} q - Parsed query from parseQuery()
212
+ */
213
+ function highlightMatch(text, q) {
214
+ if (!text || !q) return text;
215
+
216
+ var textLower = text.toLowerCase();
217
+ var query = q.normalized;
218
+
219
+ // Try contiguous match first (prefix or substring)
220
+ var matchIndex = textLower.indexOf(query);
221
+ if (matchIndex !== -1) {
222
+ return text.substring(0, matchIndex) +
223
+ '\u0001' + text.substring(matchIndex, matchIndex + query.length) + '\u0002' +
224
+ text.substring(matchIndex + query.length);
225
+ }
226
+
227
+ // Fall back to fuzzy highlight (highlight each matched character)
228
+ var result = '';
229
+ var ti = 0;
230
+ for (var qi = 0; qi < query.length; qi++) {
231
+ var charIndex = textLower.indexOf(query[qi], ti);
232
+ if (charIndex === -1) return text;
233
+ result += text.substring(ti, charIndex);
234
+ result += '\u0001' + text[charIndex] + '\u0002';
235
+ ti = charIndex + 1;
236
+ }
237
+ result += text.substring(ti);
238
+ return result;
239
+ }
@@ -0,0 +1,112 @@
1
+ (function() {
2
+ 'use strict';
3
+
4
+ const STORAGE_KEY = 'rdoc-theme';
5
+ const THEME_LIGHT = 'light';
6
+ const THEME_DARK = 'dark';
7
+
8
+ /**
9
+ * Get the user's theme preference
10
+ * Priority: localStorage > system preference > light (default)
11
+ */
12
+ function getThemePreference() {
13
+ // Check localStorage first
14
+ const stored = localStorage.getItem(STORAGE_KEY);
15
+ if (stored === THEME_LIGHT || stored === THEME_DARK) {
16
+ return stored;
17
+ }
18
+
19
+ // Check system preference
20
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
21
+ return THEME_DARK;
22
+ }
23
+
24
+ return THEME_LIGHT;
25
+ }
26
+
27
+ /**
28
+ * Apply theme to document
29
+ */
30
+ function applyTheme(theme) {
31
+ document.documentElement.setAttribute('data-theme', theme);
32
+ localStorage.setItem(STORAGE_KEY, theme);
33
+
34
+ // Update toggle button icon
35
+ const toggleBtn = document.getElementById('theme-toggle');
36
+ if (toggleBtn) {
37
+ const icon = toggleBtn.querySelector('.theme-toggle-icon');
38
+ if (icon) {
39
+ icon.textContent = theme === THEME_DARK ? '☀️' : '🌙';
40
+ }
41
+ toggleBtn.setAttribute('aria-label',
42
+ theme === THEME_DARK ? 'Switch to light mode' : 'Switch to dark mode'
43
+ );
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Toggle between light and dark themes
49
+ */
50
+ function toggleTheme() {
51
+ const currentTheme = document.documentElement.getAttribute('data-theme') || THEME_LIGHT;
52
+ const newTheme = currentTheme === THEME_LIGHT ? THEME_DARK : THEME_LIGHT;
53
+ applyTheme(newTheme);
54
+
55
+ // Announce to screen readers
56
+ announceThemeChange(newTheme);
57
+ }
58
+
59
+ /**
60
+ * Announce theme change to screen readers
61
+ */
62
+ function announceThemeChange(theme) {
63
+ const announcement = document.createElement('div');
64
+ announcement.setAttribute('role', 'status');
65
+ announcement.setAttribute('aria-live', 'polite');
66
+ announcement.className = 'sr-only';
67
+ announcement.textContent = `Switched to ${theme} mode`;
68
+ document.body.appendChild(announcement);
69
+
70
+ // Remove after announcement
71
+ setTimeout(() => {
72
+ document.body.removeChild(announcement);
73
+ }, 1000);
74
+ }
75
+
76
+ /**
77
+ * Initialize theme on page load
78
+ */
79
+ function initTheme() {
80
+ // Apply theme immediately to prevent flash
81
+ const theme = getThemePreference();
82
+ applyTheme(theme);
83
+
84
+ // Set up toggle button listener
85
+ const toggleBtn = document.getElementById('theme-toggle');
86
+ if (toggleBtn) {
87
+ toggleBtn.addEventListener('click', toggleTheme);
88
+ }
89
+
90
+ // Listen for system theme changes
91
+ if (window.matchMedia) {
92
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
93
+ // Only auto-switch if user hasn't manually set a preference
94
+ const stored = localStorage.getItem(STORAGE_KEY);
95
+ if (!stored) {
96
+ applyTheme(e.matches ? THEME_DARK : THEME_LIGHT);
97
+ }
98
+ });
99
+ }
100
+ }
101
+
102
+ // Initialize immediately (before DOMContentLoaded to prevent flash)
103
+ if (document.readyState === 'loading') {
104
+ // Apply theme as early as possible
105
+ const theme = getThemePreference();
106
+ document.documentElement.setAttribute('data-theme', theme);
107
+
108
+ document.addEventListener('DOMContentLoaded', initTheme);
109
+ } else {
110
+ initTheme();
111
+ }
112
+ })();
@@ -0,0 +1,18 @@
1
+ <body role="document" class="file has-toc">
2
+ <%= render '_icons.rhtml' %>
3
+ <%= render '_header.rhtml' %>
4
+ <%= render '_sidebar_toggle.rhtml' %>
5
+
6
+ <nav id="navigation" role="navigation" hidden>
7
+ <%= render '_sidebar_pages.rhtml' %>
8
+ <%= render '_sidebar_classes.rhtml' %>
9
+ </nav>
10
+
11
+ <main role="main" aria-label="Page <%= h file.full_name %>">
12
+ <%= file.description %>
13
+ </main>
14
+
15
+ <%= render '_aside_toc.rhtml' %>
16
+
17
+ <%= render '_footer.rhtml' %>
18
+ </body>
@@ -0,0 +1,14 @@
1
+ <body role="document">
2
+ <%= render '_sidebar_toggle.rhtml' %>
3
+
4
+ <nav id="navigation" role="navigation" hidden>
5
+ <%= render '_sidebar_pages.rhtml' %>
6
+ <%= render '_sidebar_classes.rhtml' %>
7
+ </nav>
8
+
9
+ <main role="main">
10
+ <h1>Not Found</h1>
11
+
12
+ <p><%= message %></p>
13
+ </main>
14
+ </body>
@@ -0,0 +1,65 @@
1
+ <body role="document">
2
+ <%= render '_sidebar_toggle.rhtml' %>
3
+
4
+ <nav id="navigation" role="navigation" hidden>
5
+ <div id="project-navigation">
6
+ <div id="home-section" class="nav-section">
7
+ <h2>
8
+ <a href="<%= rel_prefix %>/" rel="home">Home</a>
9
+ </h2>
10
+ </div>
11
+
12
+ <%= render '_sidebar_search.rhtml' %>
13
+ </div>
14
+
15
+ <%= render '_sidebar_installed.rhtml' %>
16
+ </nav>
17
+
18
+ <main role="main">
19
+ <h1>Local RDoc Documentation</h1>
20
+
21
+ <p>Here you can browse local documentation from the ruby standard library and
22
+ your installed gems.</p>
23
+
24
+ <%- extra_dirs = installed.select { |_, _, _, type,| type == :extra } %>
25
+ <%- unless extra_dirs.empty? %>
26
+ <h2>Extra Documentation Directories</h2>
27
+
28
+ <p>The following additional documentation directories are available:</p>
29
+
30
+ <ol>
31
+ <%- extra_dirs.each do |name, href, exists, _, path| %>
32
+ <li>
33
+ <%- if exists %>
34
+ <a href="<%= href %>"><%= h name %></a> (<%= h path %>)
35
+ <%- else %>
36
+ <%= h name %> (<%= h path %>; <i>not available</i>)
37
+ <%- end %>
38
+ </li>
39
+ <%- end %>
40
+ </ol>
41
+ <%- end %>
42
+
43
+ <%- gems = installed.select { |_, _, _, type,| type == :gem } %>
44
+ <%- missing = gems.reject { |_, _, exists,| exists } %>
45
+ <%- unless missing.empty? then %>
46
+ <h2>Missing Gem Documentation</h2>
47
+
48
+ <p>You are missing documentation for some of your installed gems.
49
+ You can install missing documentation for gems by running
50
+ <kbd>gem rdoc --all</kbd>. After installing the missing documentation you
51
+ only need to reload this page. The newly created documentation will
52
+ automatically appear.</p>
53
+
54
+ <p>You can also install documentation for a specific gem by running one of
55
+ the following commands.</p>
56
+
57
+ <ul>
58
+ <%- names = missing.map { |name,| name.sub(/-([^-]*)$/, '') }.uniq %>
59
+ <%- names.each do |name| %>
60
+ <li><kbd>gem rdoc <%= h name %></kbd></li>
61
+ <%- end %>
62
+ </ul>
63
+ <%- end %>
64
+ </main>
65
+ </body>
@@ -16,13 +16,8 @@
16
16
  <meta name="description" content="<%= h "#{file.page_name}: #{excerpt(file.comment)}" %>">
17
17
  <%- elsif @title %>
18
18
  <meta name="keywords" content="ruby,documentation,<%= h @title %>">
19
-
20
- <%- if @options.main_page and
21
- main_page = @files.find { |f| f.full_name == @options.main_page } then %>
22
- <meta name="description" content="<%= h "#{@title}: #{excerpt(main_page.comment)}" %>">
23
- <%- else %>
24
- <meta name="description" content="Documentation for <%= h @title %>">
25
- <%- end %>
19
+ <% description = @main_page ? "#{@title}: #{excerpt(@main_page.comment)}" : "Documentation for #{@title}" %>
20
+ <meta name="description" content="<%= h description %>">
26
21
  <%- end %>
27
22
 
28
23
  <%- if canonical_url = @options.canonical_root %>
@@ -13,7 +13,7 @@
13
13
  <%- f = files.shift %>
14
14
  <%- if files.empty? %>
15
15
  <li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a></li>
16
- <%- next %>
16
+ <%- next -%>
17
17
  <%- end %>
18
18
  <li><details<%= ' open' if dir == n %>><summary><%
19
19
  if n == f.page_name
@@ -4,6 +4,7 @@
4
4
  <input id="search-field" role="combobox" aria-label="Search"
5
5
  aria-autocomplete="list" aria-controls="search-results"
6
6
  type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false"
7
+ autocomplete="off"
7
8
  title="Type to search, Up and Down to navigate, Enter to load">
8
9
  </div>
9
10
 
@@ -33,6 +33,7 @@
33
33
  </ol>
34
34
  <% end %>
35
35
 
36
+ <span id="<%= h klass.legacy_aref %>" class="legacy-anchor"></span>
36
37
  <h1 id="<%= h klass.aref %>" class="anchor-link <%= klass.type %>">
37
38
  <%= klass.type %> <%= klass.full_name %>
38
39
  </h1>
@@ -42,6 +43,7 @@
42
43
  </section>
43
44
 
44
45
  <%- klass.each_section do |section, constants, attributes| %>
46
+ <span id="<%= section.legacy_aref %>" class="legacy-anchor"></span>
45
47
  <section id="<%= section.aref %>" class="documentation-section anchor-link">
46
48
  <%- if section.title then %>
47
49
  <header class="documentation-section-title">
@@ -117,10 +119,10 @@
117
119
  </section>
118
120
  <%- end %>
119
121
 
120
- <%- klass.methods_by_type(section).each do |type, visibilities|
121
- next if visibilities.empty?
122
- visibilities.each do |visibility, methods|
123
- next if methods.empty? %>
122
+ <%- klass.methods_by_type(section).each do |type, visibilities| %>
123
+ <%- next if visibilities.empty? %>
124
+ <%- visibilities.each do |visibility, methods| %>
125
+ <%- next if methods.empty? %>
124
126
  <section id="<%= visibility %>-<%= type %>-<%= section.aref %>-method-details" class="method-section anchor-link">
125
127
  <header>
126
128
  <h3><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
@@ -163,15 +165,13 @@
163
165
  <summary>Source</summary>
164
166
  </details>
165
167
  </div>
168
+ <div class="method-source-code" id="<%= method.html_name %>-source">
169
+ <pre><%= method.markup_code %></pre>
170
+ </div>
166
171
  <%- end %>
167
172
 
168
173
  <%- unless method.skip_description? then %>
169
174
  <div class="method-description">
170
- <%- if method.token_stream then %>
171
- <div class="method-source-code" id="<%= method.html_name %>-source">
172
- <pre><%= method.markup_code %></pre>
173
- </div>
174
- <%- end %>
175
175
  <%- if method.mixin_from then %>
176
176
  <div class="mixin-from">
177
177
  <%= method.singleton ? "Extended" : "Included" %> from <a href="<%= klass.aref_to(method.mixin_from.path) %>"><%= method.mixin_from.full_name %></a>
@@ -215,8 +215,8 @@
215
215
 
216
216
  <%- end %>
217
217
  </section>
218
- <%- end
219
- end %>
218
+ <%- end %>
219
+ <%- end %>
220
220
  </section>
221
221
  <%- end %>
222
222
  </main>
@@ -92,6 +92,25 @@ main .anchor-link:target {
92
92
  scroll-margin-top: 1rem;
93
93
  }
94
94
 
95
+ /* Legacy anchor for backward compatibility with old label- prefix links */
96
+ .legacy-anchor {
97
+ display: block;
98
+ position: relative;
99
+ visibility: hidden;
100
+ scroll-margin-top: 1rem;
101
+ }
102
+
103
+ /* When a legacy anchor is targeted, highlight the next heading sibling */
104
+ .legacy-anchor:target + h1,
105
+ .legacy-anchor:target + h2,
106
+ .legacy-anchor:target + h3,
107
+ .legacy-anchor:target + h4,
108
+ .legacy-anchor:target + h5,
109
+ .legacy-anchor:target + h6 {
110
+ margin-left: -10px;
111
+ border-left: 10px solid var(--border-color);
112
+ }
113
+
95
114
  /* 4. Links */
96
115
  a {
97
116
  color: var(--link-color);
@@ -47,7 +47,7 @@
47
47
  unless table.empty? then %>
48
48
  <ul>
49
49
  <%- table.each do |item| %>
50
- <%- label = item.respond_to?(:label) ? item.label(klass) : item.aref %>
50
+ <%- label = item.respond_to?(:label) ? item.label(klass) : item.aref %>
51
51
  <li><a href="<%= klass.path %>#<%= label %>"><%= item.plain_html %></a></li>
52
52
  <%- end %>
53
53
  </ul>
@@ -57,10 +57,14 @@ Searcher.prototype = new function() {
57
57
  }
58
58
 
59
59
  function buildRegexps(queries) {
60
+ // A small minority of older browsers don't have RegExp.escape
61
+ // but it's not worth including a complex polyfill.
62
+ var escape = RegExp.escape || function(s) { return s };
63
+
60
64
  return queries.map(function(query) {
61
65
  var pattern = [];
62
66
  for (var i = 0; i < query.length; i++) {
63
- var char = RegExp.escape(query[i]);
67
+ var char = escape(query[i]);
64
68
  pattern.push('([' + char + '])([^' + char + ']*?)');
65
69
  }
66
70
  return new RegExp(pattern.join(''), 'i');
@@ -43,6 +43,7 @@ module RDoc::Generator
43
43
 
44
44
  autoload :Markup, "#{__dir__}/generator/markup"
45
45
 
46
+ autoload :Aliki, "#{__dir__}/generator/aliki"
46
47
  autoload :Darkfish, "#{__dir__}/generator/darkfish"
47
48
  autoload :JsonIndex, "#{__dir__}/generator/json_index"
48
49
  autoload :RI, "#{__dir__}/generator/ri"
@@ -490,11 +490,7 @@
490
490
  # Wraps `text` in strike markup for rdoc inline formatting
491
491
 
492
492
  def strike text
493
- if text =~ /\A[a-z\d.\/-]+\z/i then
494
- "~#{text}~"
495
- else
496
- "<s>#{text}</s>"
497
- end
493
+ "<del>#{text}</del>"
498
494
  end
499
495
 
500
496
  ##
data/lib/rdoc/markdown.rb CHANGED
@@ -875,11 +875,7 @@ class RDoc::Markdown
875
875
  # Wraps `text` in strike markup for rdoc inline formatting
876
876
 
877
877
  def strike text
878
- if text =~ /\A[a-z\d.\/-]+\z/i then
879
- "~#{text}~"
880
- else
881
- "<s>#{text}</s>"
882
- end
878
+ "<del>#{text}</del>"
883
879
  end
884
880
 
885
881
  ##